more htmx utilization
This commit is contained in:
parent
e6c996d7d8
commit
6e332d4b3c
6 changed files with 266 additions and 52 deletions
179
Cargo.lock
generated
179
Cargo.lock
generated
|
@ -28,6 +28,17 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.2"
|
||||
|
@ -297,6 +308,42 @@ version = "1.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
|
||||
|
||||
[[package]]
|
||||
name = "cached"
|
||||
version = "0.44.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b195e4fbc4b6862bbd065b991a34750399c119797efff72492f28a5864de8700"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"cached_proc_macro",
|
||||
"cached_proc_macro_types",
|
||||
"futures",
|
||||
"hashbrown 0.13.2",
|
||||
"instant",
|
||||
"once_cell",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cached_proc_macro"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b48814962d2fd604c50d2b9433c2a41a0ab567779ee2c02f7fba6eca1221f082"
|
||||
dependencies = [
|
||||
"cached_proc_macro_types",
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cached_proc_macro_types"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663"
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.6"
|
||||
|
@ -364,6 +411,12 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271"
|
||||
|
||||
[[package]]
|
||||
name = "common_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3f6d59c71e7dc3af60f0af9db32364d96a16e9310f3f5db2b55ed642162dd35"
|
||||
|
||||
[[package]]
|
||||
name = "config"
|
||||
version = "0.13.3"
|
||||
|
@ -456,6 +509,41 @@ dependencies = [
|
|||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive-where"
|
||||
version = "1.2.1"
|
||||
|
@ -784,7 +872,16 @@ version = "0.12.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash 0.7.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
dependencies = [
|
||||
"ahash 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -939,6 +1036,12 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
|
@ -969,6 +1072,15 @@ dependencies = [
|
|||
"hashbrown 0.14.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "interpolator"
|
||||
version = "0.5.0"
|
||||
|
@ -1150,6 +1262,36 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leptos_router"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a426605f412e2489b752bd590fad789fa62547e18e00cb4b5bfe53c19a33270d"
|
||||
dependencies = [
|
||||
"cached",
|
||||
"cfg-if",
|
||||
"common_macros",
|
||||
"gloo-net",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"leptos",
|
||||
"linear-map",
|
||||
"log",
|
||||
"lru",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_qs",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leptos_server"
|
||||
version = "0.4.6"
|
||||
|
@ -1171,6 +1313,16 @@ version = "0.2.147"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "linear-map"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
|
@ -1199,6 +1351,15 @@ version = "0.4.19"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670"
|
||||
dependencies = [
|
||||
"hashbrown 0.13.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
|
@ -1370,6 +1531,7 @@ dependencies = [
|
|||
"futures",
|
||||
"headers",
|
||||
"leptos",
|
||||
"leptos_router",
|
||||
"rand",
|
||||
"reqwest",
|
||||
"sanitize-filename-reader-friendly",
|
||||
|
@ -1998,6 +2160,15 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_test"
|
||||
version = "1.0.176"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
|
@ -2141,6 +2312,12 @@ version = "0.9.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
|
|
|
@ -5,6 +5,7 @@ edition = "2021"
|
|||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
[dependencies]
|
||||
async-bincode = { version = "0.7.0", features = ["tokio"] }
|
||||
async_zip = { version = "0.0.13", features = ["deflate", "tokio", "tokio-fs", "async-compression"] }
|
||||
|
@ -14,6 +15,7 @@ chrono = { version = "0.4.24", features = ["serde"] }
|
|||
futures = "0.3.28"
|
||||
headers = "0.3.8"
|
||||
leptos = { version = "0.4.6", features = ["ssr", "nightly", "tracing", "default-tls"] }
|
||||
leptos_router = { version = "0.4.6", features = ["ssr"] }
|
||||
rand = { version = "0.8.5", features = ["small_rng"] }
|
||||
reqwest = { version = "0.11.18", features = ["json", "native-tls", "blocking"] }
|
||||
sanitize-filename-reader-friendly = "2.2.1"
|
||||
|
|
2
dist/css/main.css
vendored
2
dist/css/main.css
vendored
|
@ -10,7 +10,7 @@ body {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.main-form {
|
||||
.column-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
|
3
dist/scripts/loading_progress.js
vendored
Normal file
3
dist/scripts/loading_progress.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
htmx.on('#form', 'htmx:xhr:progress', function(evt) {
|
||||
htmx.find('#progress').setAttribute('value', evt.detail.loaded / evt.detail.total * 100)
|
||||
});
|
30
src/main.rs
30
src/main.rs
|
@ -3,9 +3,9 @@ use async_zip::{tokio::write::ZipFileWriter, Compression, ZipEntryBuilder};
|
|||
use axum::{
|
||||
body::StreamBody,
|
||||
extract::{ConnectInfo, DefaultBodyLimit, Multipart, State},
|
||||
http::{Request, StatusCode},
|
||||
http::{Request, Response, StatusCode},
|
||||
middleware::{self, Next},
|
||||
response::{Html, IntoResponse, Redirect, Response},
|
||||
response::{Html, IntoResponse, Redirect},
|
||||
routing::{get, post},
|
||||
Json, Router, TypedHeader,
|
||||
};
|
||||
|
@ -36,7 +36,7 @@ mod views;
|
|||
|
||||
use state::{AppState, UploadRecord};
|
||||
|
||||
use crate::views::{DownloadLink, Welcome};
|
||||
use crate::views::{DownloadLinkPage, LinkView, Welcome};
|
||||
|
||||
pub mod error {
|
||||
use std::io::{Error, ErrorKind};
|
||||
|
@ -67,6 +67,7 @@ async fn main() -> io::Result<()> {
|
|||
let state = state.clone();
|
||||
async move {
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_secs(15 * 60)).await;
|
||||
tracing::info!("Cleaning Sweep!");
|
||||
|
||||
let mut records = state.records.lock().await;
|
||||
|
@ -79,8 +80,6 @@ async fn main() -> io::Result<()> {
|
|||
cache::write_to_cache(&records).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
tokio::time::sleep(Duration::from_secs(15 * 60)).await
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -150,7 +149,7 @@ async fn link(
|
|||
return Ok(Html(leptos::ssr::render_to_string({
|
||||
let record = record.clone();
|
||||
|cx| {
|
||||
leptos::view! { cx, <DownloadLink id=id record=record /> }
|
||||
leptos::view! { cx, <DownloadLinkPage id=id record=record /> }
|
||||
}
|
||||
})));
|
||||
} else {
|
||||
|
@ -168,7 +167,7 @@ async fn log_source<B>(
|
|||
forwarded_for: Option<TypedHeader<ForwardedFor>>,
|
||||
req: Request<B>,
|
||||
next: Next<B>,
|
||||
) -> Response {
|
||||
) -> impl IntoResponse {
|
||||
tracing::info!("{} : {:?}", addr, forwarded_for);
|
||||
|
||||
next.run(req).await
|
||||
|
@ -177,7 +176,7 @@ async fn log_source<B>(
|
|||
async fn upload_to_zip(
|
||||
State(state): State<AppState>,
|
||||
mut body: Multipart,
|
||||
) -> Result<Redirect, (StatusCode, String)> {
|
||||
) -> Result<Response<String>, (StatusCode, String)> {
|
||||
tracing::debug!("{:?}", *state.records.lock().await);
|
||||
|
||||
let cache_name = util::get_random_name(10);
|
||||
|
@ -222,7 +221,8 @@ async fn upload_to_zip(
|
|||
}
|
||||
|
||||
let mut records = state.records.lock().await;
|
||||
records.insert(cache_name.clone(), UploadRecord::new(archive_path));
|
||||
let record = UploadRecord::new(archive_path);
|
||||
records.insert(cache_name.clone(), record.clone());
|
||||
|
||||
cache::write_to_cache(&records)
|
||||
.await
|
||||
|
@ -230,7 +230,17 @@ async fn upload_to_zip(
|
|||
|
||||
writer.close().await.unwrap();
|
||||
|
||||
Ok(Redirect::to(&format!("/link/{}", cache_name)))
|
||||
let id = cache_name;
|
||||
let response = Response::builder()
|
||||
.status(200)
|
||||
.header("Content-Type", "text/html")
|
||||
.header("HX-Push-Url", format!("/link/{}", &id))
|
||||
.body(leptos::ssr::render_to_string(|cx| {
|
||||
leptos::view! { cx, <LinkView id record /> }
|
||||
}))
|
||||
.unwrap();
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
async fn download(
|
||||
|
|
102
src/views.rs
102
src/views.rs
|
@ -1,5 +1,5 @@
|
|||
use futures::TryFutureExt;
|
||||
use leptos::{Children, IntoView};
|
||||
use leptos::{component, view, Children, IntoAttribute, IntoView, Scope};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::state::UploadRecord;
|
||||
|
@ -19,36 +19,77 @@ pub async fn get_cat_fact() -> String {
|
|||
|
||||
// {https://api.thecatapi.com/v1/images/search?size=small&format=src}
|
||||
// {https://cataas.com/cat?width=250&height=250}
|
||||
#[leptos::component]
|
||||
pub fn Welcome(cx: leptos::Scope, fact: String) -> impl IntoView {
|
||||
leptos::view! { cx,
|
||||
#[component]
|
||||
pub fn Welcome(cx: Scope, fact: String) -> impl IntoView {
|
||||
view! { cx,
|
||||
<HtmxPage>
|
||||
<h1>NyaZoom<sup>2</sup></h1>
|
||||
<div class="form-wrapper">
|
||||
<form action="/upload" method="post" enctype="multipart/form-data" class="main-form">
|
||||
<div class="cat-img-wrapper">
|
||||
<img class="cat-img" src="https://api.thecatapi.com/v1/images/search?size=small&format=src" />
|
||||
</div>
|
||||
|
||||
<input type="file" id="file" name="file" data-multiple-caption="{count} files selected" multiple />
|
||||
<label for="file">Select Files</label>
|
||||
|
||||
<input type="submit" value="Get Link~" />
|
||||
<p id="cat-fact">{fact}</p>
|
||||
</form>
|
||||
<WelcomeView fact />
|
||||
</div>
|
||||
</HtmxPage>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn WelcomeView(cx: Scope, fact: String) -> impl IntoView {
|
||||
view! {
|
||||
cx,
|
||||
<form id="form" hx-swap="outerHTML" hx-post="/upload" hx-encoding="multipart/form-data" class="column-container">
|
||||
<div class="cat-img-wrapper">
|
||||
<img class="cat-img" src="https://api.thecatapi.com/v1/images/search?size=small&format=src" />
|
||||
</div>
|
||||
<input type="file" id="file" name="file" data-multiple-caption="{{count}} files selected" multiple />
|
||||
<label for="file">Select Files</label>
|
||||
|
||||
<input type="submit" value="Get Link~" />
|
||||
<p id="cat-fact">{fact}</p>
|
||||
<progress id="progress" class="htmx-indicator" value="0" max="100"></progress>
|
||||
</form>
|
||||
<script src="/scripts/loading_progress.js" />
|
||||
}
|
||||
}
|
||||
|
||||
// <link href="../dist/css/link.css" rel="stylesheet" />
|
||||
// #TODO: Handle pushing cleaner
|
||||
#[leptos::component]
|
||||
pub fn DownloadLink(cx: leptos::Scope, id: String, record: UploadRecord) -> impl IntoView {
|
||||
#[component]
|
||||
pub fn DownloadLinkPage(cx: Scope, id: String, record: UploadRecord) -> impl IntoView {
|
||||
view! { cx,
|
||||
<HtmxPage>
|
||||
<div class="form-wrapper">
|
||||
<LinkView id record />
|
||||
</div>
|
||||
</HtmxPage>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn HtmxPage(cx: Scope, children: Children) -> impl IntoView {
|
||||
view! { cx,
|
||||
<head>
|
||||
<title>Nyazoom</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link href="/css/main.css" rel="stylesheet" />
|
||||
<link href="/css/link.css" rel="stylesheet" />
|
||||
<script src="/scripts/file_label.js" />
|
||||
<script src="/scripts/link.js" />
|
||||
<script src="https://unpkg.com/htmx.org@1.9.4" integrity="sha384-zUfuhFKKZCbHTY6aRR46gxiqszMk5tcHjsVFxnUo8VMus4kHGVdIYVbOYYNlKmHV" crossorigin="anonymous"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>NyaZoom<sup>2</sup></h1>
|
||||
{children(cx)}
|
||||
</body>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn LinkView(cx: Scope, id: String, record: UploadRecord) -> impl IntoView {
|
||||
let downloads_remaining = record.max_downloads - record.downloads;
|
||||
let plural = if downloads_remaining > 1 { "s" } else { "" };
|
||||
leptos::view! { cx,
|
||||
<HtmxPage>
|
||||
view! {
|
||||
cx,
|
||||
<div class="column-container">
|
||||
<div class="link-wrapper">
|
||||
<a id="link" href=format!("/download/{id}")>Download Now!</a>
|
||||
</div>
|
||||
|
@ -60,25 +101,6 @@ pub fn DownloadLink(cx: leptos::Scope, id: String, record: UploadRecord) -> impl
|
|||
|
||||
|
||||
<a href="/" class="return-button">Return to home</a>
|
||||
</HtmxPage>
|
||||
}
|
||||
}
|
||||
|
||||
#[leptos::component]
|
||||
pub fn HtmxPage(cx: leptos::Scope, children: Children) -> impl IntoView {
|
||||
leptos::view! { cx,
|
||||
<head>
|
||||
<title>Nyazoom</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link href="/css/main.css" rel="stylesheet" />
|
||||
<link href="/css/link.css" rel="stylesheet" />
|
||||
<script src="/scripts/file_label.js" />
|
||||
<script src="/scripts/link.js" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{children(cx)}
|
||||
</body>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue