feat: ✨ send message through htmx
This commit is contained in:
parent
b87ca298e9
commit
5969f7b57c
8 changed files with 198 additions and 110 deletions
102
Cargo.lock
generated
102
Cargo.lock
generated
|
@ -25,9 +25,6 @@ checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
|
|||
dependencies = [
|
||||
"askama_derive",
|
||||
"askama_escape",
|
||||
"humansize",
|
||||
"num-traits",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -37,12 +34,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn",
|
||||
]
|
||||
|
||||
|
@ -61,12 +56,6 @@ dependencies = [
|
|||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.8.1"
|
||||
|
@ -90,7 +79,6 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
|
@ -98,7 +86,6 @@ dependencies = [
|
|||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -118,7 +105,6 @@ dependencies = [
|
|||
"sync_wrapper",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -136,15 +122,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "bytes"
|
||||
version = "1.10.1"
|
||||
|
@ -257,15 +234,6 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "humansize"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
|
||||
dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.6.0"
|
||||
|
@ -313,18 +281,6 @@ version = "0.2.170"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "matchit"
|
||||
version = "0.8.4"
|
||||
|
@ -343,6 +299,8 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"askama",
|
||||
"axum",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -397,15 +355,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
|
@ -415,12 +364,6 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
|
@ -477,36 +420,24 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.218"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.218"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"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]]
|
||||
name = "serde_path_to_error"
|
||||
version = "0.1.17"
|
||||
|
@ -601,7 +532,6 @@ dependencies = [
|
|||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -616,26 +546,6 @@ version = "0.3.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "unicase"
|
||||
version = "2.8.1"
|
||||
|
|
|
@ -4,5 +4,7 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
askama = "0.12.1"
|
||||
axum = "0.8.1"
|
||||
askama = { version = "0.12.1", default-features = false }
|
||||
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
75
assests/main.css
Normal 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
13
src/lib.rs
Normal 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();
|
||||
}
|
15
src/main.rs
15
src/main.rs
|
@ -1,15 +1,8 @@
|
|||
use askama::Template;
|
||||
use message_box::start;
|
||||
|
||||
#[derive(Debug, Template)]
|
||||
#[template(path = "hello.html")]
|
||||
struct Hello<'a> {
|
||||
name: &'a str,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
println!("Hello, world!");
|
||||
|
||||
let hello = Hello { name: "Tahinli" };
|
||||
|
||||
println!("{}", hello.render().unwrap());
|
||||
start().await;
|
||||
}
|
||||
|
|
64
src/routing.rs
Normal file
64
src/routing.rs
Normal 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())),
|
||||
}
|
||||
}
|
|
@ -1 +1,5 @@
|
|||
Hello, {{name}}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
Hello {{name}}
|
||||
|
||||
</html>
|
||||
|
|
27
templates/main_page.html
Normal file
27
templates/main_page.html
Normal 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>
|
Loading…
Add table
Add a link
Reference in a new issue