mirror of
https://github.com/kristoferssolo/cipher-workshop.git
synced 2025-12-20 11:04:38 +00:00
refactor(web): make smaller components
This commit is contained in:
parent
486f8957eb
commit
bb7ef246f8
@ -4,15 +4,15 @@ use thiserror::Error;
|
|||||||
#[derive(Debug, Error, Clone, PartialEq, Eq)]
|
#[derive(Debug, Error, Clone, PartialEq, Eq)]
|
||||||
pub enum CipherError {
|
pub enum CipherError {
|
||||||
/// Invalid key size for the cipher
|
/// Invalid key size for the cipher
|
||||||
#[error("Invalid key size: expected {expected} bytes, got {actual}")]
|
#[error("Invalid key size: expected {expected} bytes, got {actual}.")]
|
||||||
InvalidKeySize { expected: usize, actual: usize },
|
InvalidKeySize { expected: usize, actual: usize },
|
||||||
|
|
||||||
/// Input data doesn't match the cipher's block size
|
/// Input data doesn't match the cipher's block size
|
||||||
#[error("Invalid block size: expected {expected} bytes, got {actual}")]
|
#[error("Invalid block size: expected {expected} bytes, got {actual}.")]
|
||||||
InvalidBlockSize { expected: usize, actual: usize },
|
InvalidBlockSize { expected: usize, actual: usize },
|
||||||
|
|
||||||
/// Error parsing block from string
|
/// Error parsing block from string
|
||||||
#[error("Error parsing block from string: {0}")]
|
#[error("{0}")]
|
||||||
BlockParseError(#[from] BlockError),
|
BlockParseError(#[from] BlockError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -50,6 +50,65 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<div class="cipher-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>{algorithm.to_string()}</h2>
|
||||||
|
</div>
|
||||||
|
<ConfigurationSection
|
||||||
|
mode=mode
|
||||||
|
set_mode=set_mode
|
||||||
|
output_fmt=output_fmt
|
||||||
|
update_output=update_output
|
||||||
|
/>
|
||||||
|
<KeyInput set_key_input=set_key_input />
|
||||||
|
<TextInput mode=mode set_text_input=set_text_input />
|
||||||
|
|
||||||
|
<button class="btn-primary" on:click=move |_| handle_submit()>
|
||||||
|
{move || format!("{} using {algorithm}", mode.get())}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<OutputBox
|
||||||
|
output=output
|
||||||
|
output_fmt=output_fmt
|
||||||
|
copy_to_clipboard=copy_to_clipboard
|
||||||
|
copy_feedback=copy_feedback
|
||||||
|
/>
|
||||||
|
<ErrorBox error_msg=error_msg />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn RadioButton(
|
||||||
|
value: OperationMode,
|
||||||
|
current: ReadSignal<OperationMode>,
|
||||||
|
set_current: WriteSignal<OperationMode>,
|
||||||
|
) -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<div class="radio-button">
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="crypto-mode"
|
||||||
|
value=value.to_string()
|
||||||
|
prop:checked=move || current.get() == value
|
||||||
|
on:change=move |_| set_current.set(value)
|
||||||
|
/>
|
||||||
|
{value.to_string()}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn ConfigurationSection(
|
||||||
|
mode: ReadSignal<OperationMode>,
|
||||||
|
set_mode: WriteSignal<OperationMode>,
|
||||||
|
output_fmt: ReadSignal<OutputFormat>,
|
||||||
|
update_output: impl Fn(OutputFormat) + Copy + Send + 'static,
|
||||||
|
) -> impl IntoView {
|
||||||
let handle_format_change = move |ev| {
|
let handle_format_change = move |ev| {
|
||||||
let val = event_target_value(&ev);
|
let val = event_target_value(&ev);
|
||||||
let fmt = OutputFormat::from_str(&val).unwrap_or_default();
|
let fmt = OutputFormat::from_str(&val).unwrap_or_default();
|
||||||
@ -76,25 +135,12 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
|||||||
};
|
};
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<div class="cipher-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<h2>{algorithm.to_string()}</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>"Configuration"</label>
|
<label>"Configuration"</label>
|
||||||
<div class="controls-row">
|
<div class="controls-row">
|
||||||
<div class="radio-group">
|
<div class="radio-group">
|
||||||
<RadioButton
|
<RadioButton value=OperationMode::Encrypt current=mode set_current=set_mode />
|
||||||
value=OperationMode::Encrypt
|
<RadioButton value=OperationMode::Decrypt current=mode set_current=set_mode />
|
||||||
current=mode
|
|
||||||
set_current=set_mode
|
|
||||||
/>
|
|
||||||
<RadioButton
|
|
||||||
value=OperationMode::Decrypt
|
|
||||||
current=mode
|
|
||||||
set_current=set_mode
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{move || {
|
{move || {
|
||||||
if mode.get() != OperationMode::Decrypt {
|
if mode.get() != OperationMode::Decrypt {
|
||||||
@ -124,6 +170,12 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
|||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn KeyInput(set_key_input: WriteSignal<String>) -> impl IntoView {
|
||||||
|
view! {
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>"Secret Key"</label>
|
<label>"Secret Key"</label>
|
||||||
<input
|
<input
|
||||||
@ -133,6 +185,15 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
|||||||
on:input=move |ev| set_key_input(event_target_value(&ev))
|
on:input=move |ev| set_key_input(event_target_value(&ev))
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn TextInput(
|
||||||
|
mode: ReadSignal<OperationMode>,
|
||||||
|
set_text_input: WriteSignal<String>,
|
||||||
|
) -> impl IntoView {
|
||||||
|
view! {
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>
|
<label>
|
||||||
{move || {
|
{move || {
|
||||||
@ -149,12 +210,17 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
|||||||
on:input=move |ev| set_text_input(event_target_value(&ev))
|
on:input=move |ev| set_text_input(event_target_value(&ev))
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
<button class="btn-primary" on:click=move |_| handle_submit()>
|
#[component]
|
||||||
{move || format!("{} using {algorithm}", mode.get())}
|
fn OutputBox(
|
||||||
</button>
|
output: ReadSignal<String>,
|
||||||
|
output_fmt: ReadSignal<OutputFormat>,
|
||||||
// Output Section
|
copy_to_clipboard: impl Fn(String) + Copy + Send + 'static,
|
||||||
|
copy_feedback: ReadSignal<bool>,
|
||||||
|
) -> impl IntoView {
|
||||||
|
view! {
|
||||||
{move || {
|
{move || {
|
||||||
if output.get().is_empty() {
|
if output.get().is_empty() {
|
||||||
return view! { <span></span> }.into_any();
|
return view! { <span></span> }.into_any();
|
||||||
@ -163,10 +229,7 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
|||||||
<div class="result-box">
|
<div class="result-box">
|
||||||
<div class="result-toolbar">
|
<div class="result-toolbar">
|
||||||
<strong>"Output ("{output_fmt.get().to_string()}")"</strong>
|
<strong>"Output ("{output_fmt.get().to_string()}")"</strong>
|
||||||
<button
|
<button class="btn-copy" on:click=move |_| copy_to_clipboard(output.get())>
|
||||||
class="btn-copy"
|
|
||||||
on:click=move |_| copy_to_clipboard(output.get())
|
|
||||||
>
|
|
||||||
{move || {
|
{move || {
|
||||||
if copy_feedback.get() { "✔️ Copied" } else { "📋 Copy" }
|
if copy_feedback.get() { "✔️ Copied" } else { "📋 Copy" }
|
||||||
}}
|
}}
|
||||||
@ -177,36 +240,17 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
|||||||
}
|
}
|
||||||
.into_any()
|
.into_any()
|
||||||
}}
|
}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Error Section
|
#[component]
|
||||||
|
fn ErrorBox(error_msg: ReadSignal<String>) -> impl IntoView {
|
||||||
|
view! {
|
||||||
{move || {
|
{move || {
|
||||||
if error_msg.get().is_empty() {
|
if error_msg.get().is_empty() {
|
||||||
return view! { <span></span> }.into_any();
|
return view! { <span></span> }.into_any();
|
||||||
}
|
}
|
||||||
view! { <div class="error-box">{error_msg.get()}</div> }.into_any()
|
view! { <div class="error-box">{error_msg.get()}</div> }.into_any()
|
||||||
}}
|
}}
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
fn RadioButton(
|
|
||||||
value: OperationMode,
|
|
||||||
current: ReadSignal<OperationMode>,
|
|
||||||
set_current: WriteSignal<OperationMode>,
|
|
||||||
) -> impl IntoView {
|
|
||||||
view! {
|
|
||||||
<div class="radio-button">
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="crypto-mode"
|
|
||||||
value=value.to_string()
|
|
||||||
prop:checked=move || current.get() == value
|
|
||||||
on:change=move |_| set_current.set(value)
|
|
||||||
/>
|
|
||||||
{value.to_string()}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user