welcome leptos!

main
Zynh0722 2023-07-26 01:53:41 -07:00
parent 33ad2f14a7
commit 107c38d533
7 changed files with 1532 additions and 364 deletions

1752
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,12 +8,14 @@ edition = "2021"
[dependencies] [dependencies]
async-bincode = { version = "0.7.0", features = ["tokio"] } async-bincode = { version = "0.7.0", features = ["tokio"] }
async_zip = { version = "0.0.13", features = ["deflate", "tokio", "tokio-fs", "async-compression"] } async_zip = { version = "0.0.13", features = ["deflate", "tokio", "tokio-fs", "async-compression"] }
axum = { version = "0.6.12", features = ["multipart", "http2", "headers"] } axum = { version = "0.6.12", features = ["multipart", "http2", "headers", "macros"] }
bincode = "1.3.3" bincode = "1.3.3"
chrono = { version = "0.4.24", features = ["serde"] } chrono = { version = "0.4.24", features = ["serde"] }
futures = "0.3.28" futures = "0.3.28"
headers = "0.3.8" headers = "0.3.8"
leptos = { version = "0.4.6", features = ["ssr", "nightly", "tracing", "default-tls"] }
rand = { version = "0.8.5", features = ["small_rng"] } 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" sanitize-filename-reader-friendly = "2.2.1"
serde = { version = "1.0.160", features = ["serde_derive", "derive"] } serde = { version = "1.0.160", features = ["serde_derive", "derive"] }
serde_derive = "1.0.160" serde_derive = "1.0.160"

54
dist/index.html vendored
View File

@ -1,54 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<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">
<script>
fetch("https://catfact.ninja/fact")
.then(data => data.json())
.then(data => {
document.getElementById("cat-fact").innerHTML = data.fact;
});
</script>
<script>
document.addEventListener("DOMContentLoaded", () => {
let inputs = document.querySelectorAll('input#file');
Array.prototype.forEach.call(inputs, function (input) {
let label = input.nextElementSibling;
let labelVal = label.innerHTML;
input.addEventListener('change', function (e) {
let fileName = '';
if (this.files?.length > 1) {
fileName = this.getAttribute('data-multiple-caption')?.replace('{count}', this.files.length);
} else {
fileName = e.target.value.split('\\').pop();
}
label.innerHTML = fileName || labelVal;
});
});
}, false);
</script>
</head>
<body>
<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://cataas.com/cat?width=250&height=250" />
</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" />
</form>
</div>
</body>
</html>

5
dist/scripts/cat_fact_fetcher.js vendored Normal file
View File

@ -0,0 +1,5 @@
fetch("https://catfact.ninja/fact")
.then(data => data.json())
.then(data => {
document.getElementById("cat-fact").innerHTML = data.fact;
});

18
dist/scripts/file_label.js vendored Normal file
View File

@ -0,0 +1,18 @@
document.addEventListener("DOMContentLoaded", () => {
let inputs = document.querySelectorAll('input#file');
Array.prototype.forEach.call(inputs, function(input) {
let label = input.nextElementSibling;
let labelVal = label.innerHTML;
input.addEventListener('change', function(e) {
let fileName = '';
if (this.files?.length > 1) {
fileName = this.getAttribute('data-multiple-caption')?.replace('{count}', this.files.length);
} else {
fileName = e.target.value.split('\\').pop();
}
label.innerHTML = fileName || labelVal;
});
});
}, false);

View File

@ -5,7 +5,7 @@ use axum::{
extract::{ConnectInfo, DefaultBodyLimit, Multipart, State}, extract::{ConnectInfo, DefaultBodyLimit, Multipart, State},
http::{Request, StatusCode}, http::{Request, StatusCode},
middleware::{self, Next}, middleware::{self, Next},
response::{IntoResponse, Redirect, Response}, response::{Html, IntoResponse, Redirect, Response},
routing::{get, post}, routing::{get, post},
Router, TypedHeader, Router, TypedHeader,
}; };
@ -31,9 +31,12 @@ mod cache;
mod nyazoom_headers; mod nyazoom_headers;
mod state; mod state;
mod util; mod util;
mod views;
use state::{AppState, UploadRecord}; use state::{AppState, UploadRecord};
use crate::views::Welcome;
pub mod error { pub mod error {
use std::io::{Error, ErrorKind}; use std::io::{Error, ErrorKind};
@ -53,6 +56,8 @@ async fn main() -> io::Result<()> {
.with(tracing_subscriber::fmt::layer()) .with(tracing_subscriber::fmt::layer())
.init(); .init();
// tracing::info!("{}", get_cat_fact().await);
// uses create_dir_all to create both .cache and serve inside it in one go // uses create_dir_all to create both .cache and serve inside it in one go
util::make_dir(".cache/serve").await?; util::make_dir(".cache/serve").await?;
@ -60,6 +65,7 @@ async fn main() -> io::Result<()> {
// Router Setup // Router Setup
let app = Router::new() let app = Router::new()
.route("/", get(welcome))
.route("/upload", post(upload_to_zip)) .route("/upload", post(upload_to_zip))
.route("/download/:id", get(download)) .route("/download/:id", get(download))
.layer(DefaultBodyLimit::disable()) .layer(DefaultBodyLimit::disable())
@ -67,7 +73,7 @@ async fn main() -> io::Result<()> {
10 * 1024 * 1024 * 1024, // 10GiB 10 * 1024 * 1024 * 1024, // 10GiB
)) ))
.with_state(state) .with_state(state)
.nest_service("/", ServeDir::new("dist")) .nest_service("/dist", ServeDir::new("dist"))
.layer(TraceLayer::new_for_http()) .layer(TraceLayer::new_for_http())
.layer(middleware::from_fn(log_source)); .layer(middleware::from_fn(log_source));
@ -82,6 +88,13 @@ async fn main() -> io::Result<()> {
Ok(()) Ok(())
} }
async fn welcome() -> impl IntoResponse {
let cat_fact = views::get_cat_fact().await;
Html(leptos::ssr::render_to_string(move |cx| {
leptos::view! { cx, <Welcome fact=cat_fact /> }
}))
}
async fn log_source<B>( async fn log_source<B>(
ConnectInfo(addr): ConnectInfo<SocketAddr>, ConnectInfo(addr): ConnectInfo<SocketAddr>,
forwarded_for: Option<TypedHeader<ForwardedFor>>, forwarded_for: Option<TypedHeader<ForwardedFor>>,

46
src/views.rs Normal file
View File

@ -0,0 +1,46 @@
use futures::TryFutureExt;
use leptos::IntoView;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct CatFact {
pub fact: String,
}
pub async fn get_cat_fact() -> String {
reqwest::get("https://catfact.ninja/fact")
.and_then(|res| res.json())
.map_ok(|cf: CatFact| cf.fact)
.await
.unwrap_or_else(|_| String::from("The cat fact goddess has failed me :<"))
}
#[leptos::component]
pub fn Welcome(cx: leptos::Scope, fact: String) -> 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="dist/css/main.css" rel="stylesheet" />
<script src="dist/scripts/file_label.js" />
</head>
<body>
<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://cataas.com/cat?width=250&height=250" />
</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>
</div>
</body>
}
}