Compare commits

...

4 commits

Author SHA1 Message Date
f894373861 leptos: begone 2024-11-14 07:42:11 -08:00
ffeff8a51b askama: link list view 2024-11-14 07:42:11 -08:00
67be18f228 askama: link view 2024-11-14 07:42:11 -08:00
91655b22ed askama: switch to main
I need 0.13's fragment feature
2024-11-14 07:42:11 -08:00
14 changed files with 131 additions and 1204 deletions

1079
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -27,15 +27,6 @@ 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.4.0" headers = "0.4.0"
leptos = { version = "0.6.14", features = [
"ssr",
"nightly",
"tracing",
"default-tls",
"experimental-islands",
] }
leptos_meta = { version = "0.6.14", features = ["ssr"] }
leptos_router = { version = "0.6.14", features = ["ssr"] }
rand = { version = "0.8.5", features = ["small_rng"] } rand = { version = "0.8.5", features = ["small_rng"] }
reqwest = { version = "0.12.7", features = ["json", "native-tls", "blocking"] } reqwest = { version = "0.12.7", features = ["json", "native-tls", "blocking"] }
sanitize-filename-reader-friendly = "2.2.1" sanitize-filename-reader-friendly = "2.2.1"
@ -47,5 +38,11 @@ tower = { version = "0.5.0", features = ["util"] }
tower-http = { version = "0.5.0", features = ["fs", "trace", "limit"] } tower-http = { version = "0.5.0", features = ["fs", "trace", "limit"] }
tracing = "0.1.37" tracing = "0.1.37"
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
askama = { version = "0.12.1", features = ["with-axum"] }
askama_axum = "0.4.0" # I want to use askama's block feature, this requires unreleased 0.13
[dependencies.askama]
git = "https://github.com/djc/askama.git"
features = ["with-axum"]
[dependencies.askama_axum]
git = "https://github.com/djc/askama.git"

View file

@ -1,7 +1,7 @@
use axum::{ use axum::{
extract::{ConnectInfo, Request}, extract::{ConnectInfo, Request},
middleware::{self, Next}, middleware::{self, Next},
response::{Html, IntoResponse}, response::IntoResponse,
routing::get, routing::get,
Router, Router,
}; };
@ -12,7 +12,7 @@ use std::{io, net::SocketAddr};
use nyazoom::*; use nyazoom::*;
use util::{headers::ForwardedFor, logging, ssr, sweeper}; use util::{headers::ForwardedFor, logging, sweeper};
#[tokio::main] #[tokio::main]
async fn main() -> io::Result<()> { async fn main() -> io::Result<()> {

View file

@ -6,7 +6,7 @@ use axum::{
}; };
use reqwest::StatusCode; use reqwest::StatusCode;
use crate::{util::ssr, AppState, AsyncRemoveRecord, DownloadLinkPage}; use crate::{askama::DownloadLinkTemplate, AppState, AsyncRemoveRecord};
pub fn get_link_router() -> Router<AppState> { pub fn get_link_router() -> Router<AppState> {
// Link pages // Link pages
@ -18,7 +18,7 @@ pub fn get_link_router() -> Router<AppState> {
async fn link( async fn link(
axum::extract::Path(id): axum::extract::Path<String>, axum::extract::Path(id): axum::extract::Path<String>,
State(mut state): State<AppState>, State(mut state): State<AppState>,
) -> Result<Html<String>, Redirect> { ) -> Result<impl IntoResponse, Redirect> {
{ {
let mut records = state.records.lock().await; let mut records = state.records.lock().await;
@ -26,10 +26,10 @@ async fn link(
.get_mut(&id) .get_mut(&id)
.filter(|record| record.can_be_downloaded()) .filter(|record| record.can_be_downloaded())
{ {
return Ok(Html(ssr::render({ return Ok(DownloadLinkTemplate {
let record = record.clone(); id,
|| leptos::view! { <DownloadLinkPage id record /> } record: record.clone(),
}))); });
} }
} }

View file

@ -1,12 +1,6 @@
use axum::{ use axum::{extract::State, response::IntoResponse, routing::get, Json, Router};
extract::State,
response::{Html, IntoResponse},
routing::get,
Json, Router,
};
use leptos::CollectView;
use crate::{util::ssr, AppState, HtmxPage}; use crate::{askama::LinkListTemplate, AppState};
pub fn get_records_router() -> Router<AppState> { pub fn get_records_router() -> Router<AppState> {
// Records views // Records views
@ -24,34 +18,6 @@ pub(crate) async fn records(State(state): State<AppState>) -> impl IntoResponse
pub async fn records_links(State(state): State<AppState>) -> impl IntoResponse { pub async fn records_links(State(state): State<AppState>) -> impl IntoResponse {
let records = state.records.lock().await.clone(); let records = state.records.lock().await.clone();
let records_list_view = records let record_keys: Vec<String> = records.keys().cloned().collect();
.keys() LinkListTemplate { record_keys }
.map(|key| {
leptos::view! {
<li class="link-wrapper">
<a href="/link/{key}">{key}</a>
<button
style="margin-left: 1em;"
hx-target="closest .link-wrapper"
hx-swap="outerHTML"
hx-delete="/link/{key}"
>
"X"
</button>
</li>
}
})
.collect_view();
Html(ssr::render(move || {
leptos::view! {
<HtmxPage>
<div class="form-wrapper">
<div class="column-container">
<ul>{records_list_view}</ul>
</div>
</div>
</HtmxPage>
}
}))
} }

View file

@ -1,5 +1,6 @@
use std::path::Path; use std::path::Path;
use askama::Template;
use async_zip::{base::write::ZipFileWriter, Compression, ZipEntryBuilder}; use async_zip::{base::write::ZipFileWriter, Compression, ZipEntryBuilder};
use axum::{ use axum::{
extract::{DefaultBodyLimit, Multipart, State}, extract::{DefaultBodyLimit, Multipart, State},
@ -14,11 +15,7 @@ use tokio::io;
use tokio_util::{compat::FuturesAsyncWriteCompatExt, io::StreamReader}; use tokio_util::{compat::FuturesAsyncWriteCompatExt, io::StreamReader};
use tower_http::limit::RequestBodyLimitLayer; use tower_http::limit::RequestBodyLimitLayer;
use crate::{ use crate::{askama::DownloadLinkFragment, cache, util, AppState, UploadRecord};
cache,
util::{self, ssr},
AppState, LinkView, UploadRecord,
};
pub fn get_upload_router() -> Router<AppState> { pub fn get_upload_router() -> Router<AppState> {
// Upload needs a subrouter to increase the body limit // Upload needs a subrouter to increase the body limit
@ -92,7 +89,7 @@ async fn upload_to_zip(
.status(200) .status(200)
.header("Content-Type", "text/html") .header("Content-Type", "text/html")
.header("HX-Push-Url", format!("/link/{}", &id)) .header("HX-Push-Url", format!("/link/{}", &id))
.body(ssr::render(|| leptos::view! { <LinkView id record /> })) .body(DownloadLinkFragment { id, record }.render().unwrap())
.unwrap(); .unwrap();
Ok(response) Ok(response)

View file

@ -1,6 +1,5 @@
pub mod headers; pub mod headers;
pub mod logging; pub mod logging;
pub mod ssr;
pub mod sweeper; pub mod sweeper;
use rand::{ use rand::{

View file

@ -1,7 +0,0 @@
pub fn render<F, N>(f: F) -> String
where
F: FnOnce() -> N + 'static,
N: leptos::IntoView,
{
leptos::ssr::render_to_string(f).to_string()
}

View file

@ -1,5 +1,7 @@
use askama_axum::Template; use askama_axum::Template;
use crate::{link::get_remaining_text, UploadRecord};
#[derive(Template)] #[derive(Template)]
#[template(path = "welcome.html")] #[template(path = "welcome.html")]
pub struct WelcomeTemplate { pub struct WelcomeTemplate {
@ -11,3 +13,38 @@ impl WelcomeTemplate {
WelcomeTemplate { fact } WelcomeTemplate { fact }
} }
} }
#[derive(Template)]
#[template(path = "link.html")]
pub struct DownloadLinkTemplate {
pub id: String,
pub record: UploadRecord,
}
impl DownloadLinkTemplate {
fn get_downloads_remaining_text(record: &UploadRecord) -> String {
let downloads_remaining = record.max_downloads - record.downloads;
get_remaining_text(downloads_remaining)
}
}
#[derive(Template)]
#[template(path = "link.html", block = "content")]
pub struct DownloadLinkFragment {
pub id: String,
pub record: UploadRecord,
}
impl DownloadLinkFragment {
fn get_downloads_remaining_text(record: &UploadRecord) -> String {
let downloads_remaining = record.max_downloads - record.downloads;
get_remaining_text(downloads_remaining)
}
}
#[derive(Template)]
#[template(path = "linklist.html")]
pub struct LinkListTemplate {
pub record_keys: Vec<String>,
}

View file

@ -1,26 +0,0 @@
use leptos::{component, view, Children, IntoView};
#[component]
pub fn HtmxPage(children: Children) -> impl IntoView {
view! {
<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@2.0.2"
integrity="sha384-Y7hw+L/jvKeWIRRkqWYfPcvVxHzVzn5REgzbawhxAuQGwX1XWe70vji+VSeHOThJ"
crossorigin="anonymous"
></script>
</head>
<body>
<h1>"NyaZoom"<sup>"2"</sup></h1>
{children()}
</body>
}
}

View file

@ -1,47 +0,0 @@
use leptos::{component, view, IntoView};
use crate::link::get_remaining_text;
use crate::state::UploadRecord;
use crate::HtmxPage;
// <link href="../dist/css/link.css" rel="stylesheet" />
// #TODO: Handle pushing cleaner
#[component]
pub fn DownloadLinkPage(id: String, record: UploadRecord) -> impl IntoView {
view! {
<HtmxPage>
<div class="form-wrapper">
<LinkView id record />
</div>
</HtmxPage>
}
}
#[component]
pub fn LinkView(id: String, record: UploadRecord) -> impl IntoView {
let downloads_remaining = record.max_downloads - record.downloads;
view! {
<div class="column-container">
<div class="link-wrapper">
<a id="link" href="/download/{id}">
"Download Now!"
</a>
</div>
<div
class="link-wrapper"
hx-get="/link/{id}/remaining"
hx-trigger="click from:#link delay:0.2s, every 10s"
>
{get_remaining_text(downloads_remaining)}
</div>
<button class="return-button" onclick="clipboard()">
Copy to Clipboard
</button>
<a href="/" class="return-button">
"Return to home"
</a>
</div>
}
}

View file

@ -2,11 +2,6 @@ use futures::TryFutureExt;
use serde::Deserialize; use serde::Deserialize;
pub mod askama; pub mod askama;
pub mod base_page;
pub mod links;
pub use base_page::*;
pub use links::*;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct CatFact { pub struct CatFact {

24
templates/link.html Normal file
View file

@ -0,0 +1,24 @@
{% extends "base.html" %}
{% block content %}
<div class="form-wrapper">
<div class="column-container">
<div class="link-wrapper">
<a id="link" href="/download/{{id}}"> "Download Now!" </a>
</div>
<div
class="link-wrapper"
hx-get="/link/{{id}}/remaining"
hx-trigger="click from:#link delay:0.2s, every 10s"
>
{{Self::get_downloads_remaining_text(record)}}
</div>
<button class="return-button" onclick="clipboard()">
Copy to Clipboard
</button>
<a href="/" class="return-button"> "Return to home" </a>
</div>
</div>
{% endblock content %}

23
templates/linklist.html Normal file
View file

@ -0,0 +1,23 @@
{% extends "base.html" %}
{% block content %}
<div class="form-wrapper">
<div class="column-container">
<ul>
{% for key in record_keys %}
<li class="link-wrapper">
<a href="/link/{{ key }}">{{ key }}</a>
<button
style="margin-left: 1em;"
hx-target="closest .link-wrapper"
hx-swap="outerHTML"
hx-delete="/link/{{ key }}"
>
"X"
</button>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endblock content %}