mirror of
https://github.com/kristoferssolo/cipher-workshop.git
synced 2025-12-31 05:42:30 +00:00
Compare commits
No commits in common. "02ab1d119c5815d9ec5d0741ac27da0b01ebccb1" and "0687fe04319bfc91c6ca49b7d3d1759b73ab7c46" have entirely different histories.
02ab1d119c
...
0687fe0431
@ -1,5 +1,5 @@
|
||||
use cipher_factory::prelude::*;
|
||||
use leptos::{prelude::*, tachys::dom::event_target_value};
|
||||
use leptos::prelude::*;
|
||||
use std::{str::FromStr, time::Duration};
|
||||
use strum::IntoEnumIterator;
|
||||
use web_sys::WheelEvent;
|
||||
@ -22,20 +22,14 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
||||
set_output(String::new());
|
||||
|
||||
let key = key_input.get();
|
||||
let raw_text = text_input.get();
|
||||
let text = text_input.get();
|
||||
|
||||
if key.is_empty() || raw_text.is_empty() {
|
||||
if key.is_empty() || text.is_empty() {
|
||||
set_error_msg("Please enter both key and input text.".to_string());
|
||||
return;
|
||||
}
|
||||
|
||||
let final_text = if mode.get() == OperationMode::Decrypt {
|
||||
format!("0x{raw_text}")
|
||||
} else {
|
||||
raw_text
|
||||
};
|
||||
|
||||
let context = CipherContext::new(algorithm, mode.get(), key, final_text, output_fmt.get());
|
||||
let context = CipherContext::new(algorithm, mode.get(), key, text, output_fmt.get());
|
||||
match context.process() {
|
||||
Ok(out) => set_output(out),
|
||||
Err(e) => set_error_msg(e.to_string()),
|
||||
@ -68,7 +62,7 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
||||
update_output=update_output
|
||||
/>
|
||||
<KeyInput set_key_input=set_key_input />
|
||||
<TextInput mode=mode text_input=text_input set_text_input=set_text_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())}
|
||||
@ -179,24 +173,15 @@ fn ConfigurationSection(
|
||||
}
|
||||
}
|
||||
|
||||
fn clean_hex_input(input: String) -> String {
|
||||
input
|
||||
.chars()
|
||||
.filter(|ch| ch.is_ascii_hexdigit())
|
||||
.collect::<String>()
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn KeyInput(set_key_input: WriteSignal<String>) -> impl IntoView {
|
||||
view! {
|
||||
<div class="form-group">
|
||||
<div class="lable-header">
|
||||
<label>"Secret Key"</label>
|
||||
<span class="input-hint">"Prefix: 0x (Hex), 0b (Bin), or nothing (Text)"</span>
|
||||
</div>
|
||||
<label>"Secret Key"</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter key (e.g., 0x1A2B...)"
|
||||
prop:key_input
|
||||
placeholder="Enter key..."
|
||||
on:input=move |ev| set_key_input(event_target_value(&ev))
|
||||
/>
|
||||
</div>
|
||||
@ -206,62 +191,24 @@ fn KeyInput(set_key_input: WriteSignal<String>) -> impl IntoView {
|
||||
#[component]
|
||||
fn TextInput(
|
||||
mode: ReadSignal<OperationMode>,
|
||||
text_input: ReadSignal<String>,
|
||||
set_text_input: WriteSignal<String>,
|
||||
) -> impl IntoView {
|
||||
let handle_hex_input = move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
let cleaned = clean_hex_input(val);
|
||||
set_text_input(cleaned);
|
||||
};
|
||||
|
||||
let handle_text_input = move |ev| {
|
||||
set_text_input(event_target_value(&ev));
|
||||
};
|
||||
|
||||
view! {
|
||||
<div class="form-group">
|
||||
{move || {
|
||||
match mode.get() {
|
||||
OperationMode::Encrypt => {
|
||||
view! {
|
||||
<div class="lable-header">
|
||||
<label>"Plaintext Input"</label>
|
||||
<span class="input-hint">
|
||||
"Prefix: 0x (Hex), 0b (Bin), or nothing (Text)"
|
||||
</span>
|
||||
</div>
|
||||
<div class="input-wrapper standard-input">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter text..."
|
||||
on:input=handle_text_input
|
||||
spellcheck="false"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
<label>
|
||||
{move || {
|
||||
match mode.get() {
|
||||
OperationMode::Encrypt => "Plaintext Input",
|
||||
OperationMode::Decrypt => "Ciphertext (Hex) Input",
|
||||
}
|
||||
OperationMode::Decrypt => {
|
||||
view! {
|
||||
<div class="lable-header">
|
||||
<label>"Ciphertext Input"</label>
|
||||
</div>
|
||||
<div class="input-wrapper hex-input">
|
||||
<span class="prefix">"0x"</span>
|
||||
<input
|
||||
type="text"
|
||||
prop:value=move || text_input.get()
|
||||
placeholder="001122"
|
||||
on:input=handle_hex_input
|
||||
spellcheck="false"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
}
|
||||
}
|
||||
}}
|
||||
}}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
prop:text_input
|
||||
placeholder="Enter text..."
|
||||
on:input=move |ev| set_text_input(event_target_value(&ev))
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,35 +312,6 @@ main {
|
||||
}
|
||||
}
|
||||
|
||||
@mixin input-styles {
|
||||
width: 100%;
|
||||
background: var(--bg-input);
|
||||
color: var(--text-main);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
font-size: 1rem;
|
||||
font-family: "Consolas", "Monaco", monospace;
|
||||
box-sizing: border-box;
|
||||
|
||||
transition:
|
||||
background $trans-time,
|
||||
border-color $trans-time,
|
||||
box-shadow $trans-time,
|
||||
color $trans-time;
|
||||
|
||||
&:focus,
|
||||
&:focus-within {
|
||||
outline: none;
|
||||
border-color: var(--primary);
|
||||
box-shadow: 0 0 0 3px var(--focus-ring);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--text-muted);
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1.5rem;
|
||||
|
||||
@ -356,8 +327,15 @@ main {
|
||||
|
||||
input[type="text"],
|
||||
textarea {
|
||||
@include input-styles;
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background: var(--bg-input);
|
||||
color: var(--text-main);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
font-size: 1rem;
|
||||
box-sizing: border-box;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
@ -571,7 +549,7 @@ main {
|
||||
font-size: 6rem;
|
||||
font-weight: 800;
|
||||
color: var(--error);
|
||||
font-family: "Consolas", "Monaco", monospace;
|
||||
font-family: "Consolar", "Monaco", monospace;
|
||||
opacity: 0.8;
|
||||
line-height: 1;
|
||||
margin-bottom: 1rem;
|
||||
@ -606,68 +584,3 @@ main {
|
||||
width: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
width: 100%;
|
||||
|
||||
&.hex-input {
|
||||
@include input-styles;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
cursor: text;
|
||||
|
||||
.prefix {
|
||||
padding-left: 12px;
|
||||
padding-right: 2px;
|
||||
color: var(--text-muted);
|
||||
user-select: none;
|
||||
font-weight: bold;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
border: none;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
|
||||
padding: 12px 12px 12px 0px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.standard-input {
|
||||
input[type="text"] {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.input-hint {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-muted);
|
||||
opacity: 0.7;
|
||||
font-family: "Inter", "Segoe UI", sans-serif;
|
||||
text-transform: none;
|
||||
letter-spacing: normal;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user