feat: send message through htmx

This commit is contained in:
Ahmet Kaan Gümüş 2025-03-10 03:37:20 +03:00
parent b87ca298e9
commit 5969f7b57c
8 changed files with 198 additions and 110 deletions

102
Cargo.lock generated
View file

@ -25,9 +25,6 @@ checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
dependencies = [ dependencies = [
"askama_derive", "askama_derive",
"askama_escape", "askama_escape",
"humansize",
"num-traits",
"percent-encoding",
] ]
[[package]] [[package]]
@ -37,12 +34,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
dependencies = [ dependencies = [
"askama_parser", "askama_parser",
"basic-toml",
"mime", "mime",
"mime_guess", "mime_guess",
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde",
"syn", "syn",
] ]
@ -61,12 +56,6 @@ dependencies = [
"nom", "nom",
] ]
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]] [[package]]
name = "axum" name = "axum"
version = "0.8.1" version = "0.8.1"
@ -90,7 +79,6 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"rustversion", "rustversion",
"serde", "serde",
"serde_json",
"serde_path_to_error", "serde_path_to_error",
"serde_urlencoded", "serde_urlencoded",
"sync_wrapper", "sync_wrapper",
@ -98,7 +86,6 @@ dependencies = [
"tower", "tower",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing",
] ]
[[package]] [[package]]
@ -118,7 +105,6 @@ dependencies = [
"sync_wrapper", "sync_wrapper",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing",
] ]
[[package]] [[package]]
@ -136,15 +122,6 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "basic-toml"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.10.1" version = "1.10.1"
@ -257,15 +234,6 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "humansize"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
dependencies = [
"libm",
]
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "1.6.0" version = "1.6.0"
@ -313,18 +281,6 @@ version = "0.2.170"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
[[package]]
name = "libm"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
[[package]]
name = "log"
version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
[[package]] [[package]]
name = "matchit" name = "matchit"
version = "0.8.4" version = "0.8.4"
@ -343,6 +299,8 @@ version = "0.1.0"
dependencies = [ dependencies = [
"askama", "askama",
"axum", "axum",
"serde",
"tokio",
] ]
[[package]] [[package]]
@ -397,15 +355,6 @@ dependencies = [
"minimal-lexical", "minimal-lexical",
] ]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "object" name = "object"
version = "0.36.7" version = "0.36.7"
@ -415,12 +364,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "once_cell"
version = "1.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.1" version = "2.3.1"
@ -477,36 +420,24 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.218" version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.218" version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
] ]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]] [[package]]
name = "serde_path_to_error" name = "serde_path_to_error"
version = "0.1.17" version = "0.1.17"
@ -601,7 +532,6 @@ dependencies = [
"tokio", "tokio",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing",
] ]
[[package]] [[package]]
@ -616,26 +546,6 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"log",
"pin-project-lite",
"tracing-core",
]
[[package]]
name = "tracing-core"
version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
dependencies = [
"once_cell",
]
[[package]] [[package]]
name = "unicase" name = "unicase"
version = "2.8.1" version = "2.8.1"

View file

@ -4,5 +4,7 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
askama = "0.12.1" askama = { version = "0.12.1", default-features = false }
axum = "0.8.1" axum = { version = "0.8.1" , default-features = false, features = ["http1", "form", "tokio"] }
serde = { version = "1.0.219", default-features = false, features = ["derive"] }
tokio = { version = "1.44.0", default-features = false, features = ["rt-multi-thread"] }

75
assests/main.css Normal file
View file

@ -0,0 +1,75 @@
.main {
box-sizing: border-box;
margin: 1%;
/* @media screen { */
/* width: 50%; */
/* } */
/**/
/* @media screen and (max-width:820px) { */
/* width: 100%; */
/* } */
#name {
border-radius: 5px;
width: 10%;
font-size: x-large;
}
#email {
margin-top: 2%;
border-radius: 5px;
width: 10%;
font-size: x-large;
}
#message {
margin-top: 5%;
border-radius: 5px;
display: block;
font-size: x-large;
width: 40vh;
height: 50vh;
resize: none;
}
#send {
margin-top: 5%;
width: 10vh;
height: 5vh;
size: 10vh;
}
button:focus {
outline: none;
}
input:focus {
outline: none;
}
textarea:focus {
outline: none;
}
input:invalid {
border: 2px solid burlywood;
}
input:valid {
border: 2px solid lime;
}
textarea:invalid {
border: 2px solid burlywood;
}
textarea:valid {
border: 2px solid lime;
}
}
body {
background-color: rgba(0, 0, 0, 0.98);
color: silver;
}

13
src/lib.rs Normal file
View file

@ -0,0 +1,13 @@
use routing::route;
use tokio::net::TcpListener;
mod routing;
static CSS: &str = include_str!("../assests/main.css");
static FAVICON: &str = "";
pub async fn start() {
let router = route().await;
let listener = TcpListener::bind("0.0.0.0:2554").await.unwrap();
axum::serve(listener, router).await.unwrap();
}

View file

@ -1,15 +1,8 @@
use askama::Template; use message_box::start;
#[derive(Debug, Template)] #[tokio::main]
#[template(path = "hello.html")] async fn main() {
struct Hello<'a> {
name: &'a str,
}
fn main() {
println!("Hello, world!"); println!("Hello, world!");
let hello = Hello { name: "Tahinli" }; start().await;
println!("{}", hello.render().unwrap());
} }

64
src/routing.rs Normal file
View file

@ -0,0 +1,64 @@
use askama::Template;
use axum::{
Form, Router,
extract::Path,
http::{HeaderMap, StatusCode, header},
response::{Html, IntoResponse},
routing::{get, post},
};
use serde::{Deserialize, Serialize};
use crate::{CSS, FAVICON};
#[derive(Debug, Serialize, Deserialize, Template)]
#[template(path = "main_page.html")]
struct MainPage {
name: String,
email: String,
message: String,
}
pub async fn route() -> Router {
Router::new()
.route("/alive", get(alive))
.route("/assets/{asset_name}", get(serve_assets))
.route("/{asset_name}", get(serve_assets))
.route("/", get(main_page))
.route("/send", post(send))
}
async fn alive() -> impl IntoResponse {
(StatusCode::OK, Html("I'm alive"))
}
async fn send(Form(body): Form<MainPage>) -> impl IntoResponse {
println!("{}", body.name);
println!("{}", body.email);
println!("{}", body.message);
(StatusCode::CREATED, "Thanks for contacting!")
}
async fn serve_assets(Path(asset_name): Path<String>) -> impl IntoResponse {
let mut headers = HeaderMap::new();
if asset_name == "main.css" {
headers.insert(header::CONTENT_TYPE, "text/css".parse().unwrap());
(StatusCode::OK, headers, CSS)
} else if asset_name == "favicon.ico" {
(StatusCode::OK, headers, FAVICON)
} else {
(StatusCode::NOT_FOUND, headers, "")
}
}
async fn main_page() -> impl IntoResponse {
let main_page = MainPage {
name: String::default(),
email: String::default(),
message: String::default(),
};
match main_page.render() {
Ok(rendered) => (StatusCode::OK, Html(rendered)),
Err(err_val) => (StatusCode::SERVICE_UNAVAILABLE, Html(err_val.to_string())),
}
}

View file

@ -1 +1,5 @@
Hello, {{name}} <!DOCTYPE html>
<html>
Hello {{name}}
</html>

27
templates/main_page.html Normal file
View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<script src="https://unpkg.com/htmx.org@2.0.4"
integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+"
crossorigin="anonymous"></script>
<html>
<h1 class="main">Contact</h1>
<link rel="stylesheet" href="/assets/main.css">
<form id="form" hx-post="/send" hx-target="this" required>
<div class="main">
<input type="text" name="name" id="name" placeholder="Name" required maxlength=1024 value="{{name}}"></input>
</div>
<div class="main">
<input type="email" name="email" id="email" placeholder="Email" required maxlength=1024
value="{{email}}"></input>
</div>
<div class="main">
<textarea type="text" name="message" id="message" placeholder="Message" required minlength=16 maxlength=1024
value="{{message}}"></textarea>
</div>
<div class="main">
<button id="send" name="send" type="submit" hx-target="#form">
Send
</button>
</div>
</form>
</html>