mirror of
https://github.com/kristoferssolo/cipher-workshop.git
synced 2026-01-13 20:26:03 +00:00
refactor(web): use AnyView return type for all components
This commit is contained in:
parent
6acf98bbae
commit
4c3d620250
41
Dockerfile
41
Dockerfile
@ -1,48 +1,51 @@
|
||||
# Compute recipe
|
||||
FROM lukemathwalker/cargo-chef:latest-rust-1 AS chef
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN cargo chef prepare --recipe-path recipe.json
|
||||
|
||||
# Install tools and build dependencies
|
||||
FROM rustlang/rust:nightly-bookworm AS cacher
|
||||
WORKDIR /app
|
||||
|
||||
# Install cargo-binstall
|
||||
RUN curl -L https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz | tar -xz -C /usr/local/bin
|
||||
|
||||
RUN curl -LO https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz
|
||||
RUN tar -xvf cargo-binstall-x86_64-unknown-linux-musl.tgz
|
||||
RUN cp cargo-binstall /usr/local/cargo/bin
|
||||
RUN cargo binstall cargo-leptos cargo-chef -y
|
||||
RUN apt-get update -y && apt-get install -y --no-install-recommends clang
|
||||
RUN rustup target add wasm32-unknown-unknown
|
||||
|
||||
WORKDIR /app
|
||||
# Cook dependencies
|
||||
COPY --from=chef /app/recipe.json recipe.json
|
||||
RUN cargo chef cook --release --recipe-path recipe.json
|
||||
|
||||
# Actual build
|
||||
FROM rustlang/rust:nightly-bookworm AS builder
|
||||
|
||||
RUN wget https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz
|
||||
RUN tar -xvf cargo-binstall-x86_64-unknown-linux-musl.tgz
|
||||
RUN cp cargo-binstall /usr/local/cargo/bin
|
||||
RUN cargo binstall cargo-leptos -y
|
||||
RUN apt-get update -y && apt-get install -y --no-install-recommends clang
|
||||
RUN rustup target add wasm32-unknown-unknown
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy the tools from the cacher stage
|
||||
COPY --from=cacher /usr/local/rustup /usr/local/rustup
|
||||
COPY --from=cacher /usr/local/cargo /usr/local/cargo
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends clang
|
||||
|
||||
# Bring in the cooked dependencies
|
||||
COPY --from=cacher /app/target target
|
||||
COPY . .
|
||||
|
||||
# Build the Leptos app
|
||||
RUN cargo leptos build --release -vv
|
||||
|
||||
# Runtime
|
||||
FROM debian:bookworm-slim AS runtime
|
||||
|
||||
WORKDIR /app
|
||||
RUN apt-get update -y \
|
||||
&& apt-get install -y --no-install-recommends openssl ca-certificates \
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends openssl ca-certificates \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy binaries and assets
|
||||
COPY --from=builder /app/target/release/web /app/
|
||||
COPY --from=builder /app/target/site /app/site
|
||||
COPY --from=builder /app/Cargo.toml /app/
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["/app/web"]
|
||||
|
||||
@ -10,7 +10,7 @@ use leptos::prelude::*;
|
||||
use std::time::Duration;
|
||||
|
||||
#[component]
|
||||
pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
||||
pub fn CipherForm(algorithm: Algorithm) -> AnyView {
|
||||
let (mode, set_mode) = signal(OperationMode::Encrypt);
|
||||
let (output_fmt, set_output_fmt) = signal(OutputFormat::Hex);
|
||||
|
||||
@ -101,4 +101,5 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
||||
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ use wasm_bindgen::JsCast;
|
||||
use web_sys::{Blob, Url};
|
||||
|
||||
#[component]
|
||||
pub fn CipherFormCbc() -> impl IntoView {
|
||||
pub fn CipherFormCbc() -> AnyView {
|
||||
let (mode, set_mode) = signal(OperationMode::Encrypt);
|
||||
let (output_fmt, set_output_fmt) = signal(OutputFormat::Hex);
|
||||
|
||||
@ -56,7 +56,7 @@ pub fn CipherFormCbc() -> impl IntoView {
|
||||
let formatted_iv = format!("0x{iv}");
|
||||
|
||||
// Get input data
|
||||
let input_data: Vec<u8> = match input_mode.get() {
|
||||
let input_data = match input_mode.get() {
|
||||
InputMode::Text => {
|
||||
let text = text_content.get();
|
||||
if text.is_empty() {
|
||||
@ -192,7 +192,10 @@ pub fn CipherFormCbc() -> impl IntoView {
|
||||
<div class="result-toolbar">
|
||||
<strong>"Output ("{output_fmt.get().to_string()}")"</strong>
|
||||
<div class="result-actions">
|
||||
<button class="btn-copy" on:click=move |_| copy_to_clipboard(output.get())>
|
||||
<button
|
||||
class="btn-copy"
|
||||
on:click=move |_| copy_to_clipboard(output.get())
|
||||
>
|
||||
{move || if copy_feedback.get() { "Copied" } else { "Copy" }}
|
||||
</button>
|
||||
{move || {
|
||||
@ -201,7 +204,8 @@ pub fn CipherFormCbc() -> impl IntoView {
|
||||
<button class="btn-download" on:click=download_output>
|
||||
"Download"
|
||||
</button>
|
||||
}.into_any()
|
||||
}
|
||||
.into_any()
|
||||
} else {
|
||||
view! { <span></span> }.into_any()
|
||||
}
|
||||
@ -209,21 +213,25 @@ pub fn CipherFormCbc() -> impl IntoView {
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-content">
|
||||
<code>{move || {
|
||||
let out = output.get();
|
||||
if out.len() > 1000 {
|
||||
format!("{}... ({} chars total)", &out[..1000], out.len())
|
||||
} else {
|
||||
out
|
||||
}
|
||||
}}</code>
|
||||
<code>
|
||||
{move || {
|
||||
let out = output.get();
|
||||
if out.len() > 1000 {
|
||||
format!("{}... ({} chars total)", &out[..1000], out.len())
|
||||
} else {
|
||||
out
|
||||
}
|
||||
}}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
}.into_any()
|
||||
}
|
||||
.into_any()
|
||||
}}
|
||||
<ErrorBox error_msg=error_msg />
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
}
|
||||
|
||||
fn parse_hex_string(s: &str) -> Result<Vec<u8>, String> {
|
||||
@ -234,7 +242,7 @@ fn parse_hex_string(s: &str) -> Result<Vec<u8>, String> {
|
||||
.unwrap_or(trimmed);
|
||||
|
||||
// Remove whitespace and newlines
|
||||
let s: String = s.chars().filter(|c| !c.is_whitespace()).collect();
|
||||
let s = s.chars().filter(|c| !c.is_whitespace()).collect::<String>();
|
||||
|
||||
if !s.len().is_multiple_of(2) {
|
||||
return Err("Hex string must have even length".to_string());
|
||||
@ -282,10 +290,7 @@ fn download_bytes(bytes: &[u8], filename: &str) {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(window) = web_sys::window() else {
|
||||
return;
|
||||
};
|
||||
let Some(document) = window.document() else {
|
||||
let Some(document) = window().document() else {
|
||||
return;
|
||||
};
|
||||
let Some(a) = document.create_element("a").ok() else {
|
||||
@ -295,7 +300,7 @@ fn download_bytes(bytes: &[u8], filename: &str) {
|
||||
let _ = a.set_attribute("href", &url);
|
||||
let _ = a.set_attribute("download", filename);
|
||||
|
||||
let a: web_sys::HtmlElement = a.unchecked_into();
|
||||
let a = a.unchecked_into::<web_sys::HtmlElement>();
|
||||
a.click();
|
||||
|
||||
let _ = Url::revoke_object_url(&url);
|
||||
|
||||
@ -10,7 +10,7 @@ pub fn ConfigurationSection(
|
||||
set_mode: WriteSignal<OperationMode>,
|
||||
output_fmt: ReadSignal<OutputFormat>,
|
||||
update_output: impl Fn(OutputFormat) + Copy + Send + 'static,
|
||||
) -> impl IntoView {
|
||||
) -> AnyView {
|
||||
let handle_format_change = move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
let fmt = OutputFormat::from_str(&val).unwrap_or_default();
|
||||
@ -83,4 +83,5 @@ pub fn ConfigurationSection(
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ fn read_file(
|
||||
fn InputModeToggle(
|
||||
input_mode: ReadSignal<InputMode>,
|
||||
set_input_mode: WriteSignal<InputMode>,
|
||||
) -> impl IntoView {
|
||||
) -> AnyView {
|
||||
view! {
|
||||
<div class="input-mode-toggle">
|
||||
<button
|
||||
@ -64,6 +64,7 @@ fn InputModeToggle(
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
}
|
||||
|
||||
#[component]
|
||||
@ -71,7 +72,7 @@ fn TextAreaInput(
|
||||
text_content: ReadSignal<String>,
|
||||
set_text_content: WriteSignal<String>,
|
||||
is_decrypt_mode: Memo<bool>,
|
||||
) -> impl IntoView {
|
||||
) -> AnyView {
|
||||
let handle_text_change = move |ev: Event| {
|
||||
if let Some(target) = ev.target() {
|
||||
let textarea: web_sys::HtmlTextAreaElement = target.unchecked_into();
|
||||
@ -99,6 +100,7 @@ fn TextAreaInput(
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
}
|
||||
|
||||
#[component]
|
||||
@ -107,7 +109,7 @@ fn FileDropZone(
|
||||
set_file_data: WriteSignal<Option<Vec<u8>>>,
|
||||
file_name: ReadSignal<Option<String>>,
|
||||
set_file_name: WriteSignal<Option<String>>,
|
||||
) -> impl IntoView {
|
||||
) -> AnyView {
|
||||
let (is_dragging, set_is_dragging) = signal(false);
|
||||
|
||||
let handle_file_change = move |ev: Event| {
|
||||
@ -193,6 +195,7 @@ fn FileDropZone(
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
}
|
||||
|
||||
#[component]
|
||||
@ -201,7 +204,7 @@ fn FileSelected(
|
||||
file_data: ReadSignal<Option<Vec<u8>>>,
|
||||
set_file_name: WriteSignal<Option<String>>,
|
||||
set_file_data: WriteSignal<Option<Vec<u8>>>,
|
||||
) -> impl IntoView {
|
||||
) -> AnyView {
|
||||
let clear_file = move |ev: web_sys::MouseEvent| {
|
||||
ev.prevent_default();
|
||||
ev.stop_propagation();
|
||||
@ -221,16 +224,18 @@ fn FileSelected(
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn FilePlaceholder() -> impl IntoView {
|
||||
fn FilePlaceholder() -> AnyView {
|
||||
view! {
|
||||
<div class="file-placeholder">
|
||||
<span class="upload-icon">"[+]"</span>
|
||||
<span>"Click to select a file or drag and drop"</span>
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
}
|
||||
|
||||
#[component]
|
||||
@ -244,7 +249,7 @@ pub fn FileTextInput(
|
||||
file_name: ReadSignal<Option<String>>,
|
||||
set_file_name: WriteSignal<Option<String>>,
|
||||
is_decrypt_mode: Memo<bool>,
|
||||
) -> impl IntoView {
|
||||
) -> AnyView {
|
||||
view! {
|
||||
<div class="form-group">
|
||||
<div class="label-header">
|
||||
@ -281,4 +286,5 @@ pub fn FileTextInput(
|
||||
}}
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user