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 cipher_factory::prelude::*;
|
||||||
use leptos::{prelude::*, tachys::dom::event_target_value};
|
use leptos::prelude::*;
|
||||||
use std::{str::FromStr, time::Duration};
|
use std::{str::FromStr, time::Duration};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use web_sys::WheelEvent;
|
use web_sys::WheelEvent;
|
||||||
@ -22,20 +22,14 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
|||||||
set_output(String::new());
|
set_output(String::new());
|
||||||
|
|
||||||
let key = key_input.get();
|
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());
|
set_error_msg("Please enter both key and input text.".to_string());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let final_text = if mode.get() == OperationMode::Decrypt {
|
let context = CipherContext::new(algorithm, mode.get(), key, text, output_fmt.get());
|
||||||
format!("0x{raw_text}")
|
|
||||||
} else {
|
|
||||||
raw_text
|
|
||||||
};
|
|
||||||
|
|
||||||
let context = CipherContext::new(algorithm, mode.get(), key, final_text, output_fmt.get());
|
|
||||||
match context.process() {
|
match context.process() {
|
||||||
Ok(out) => set_output(out),
|
Ok(out) => set_output(out),
|
||||||
Err(e) => set_error_msg(e.to_string()),
|
Err(e) => set_error_msg(e.to_string()),
|
||||||
@ -68,7 +62,7 @@ pub fn CipherForm(algorithm: Algorithm) -> impl IntoView {
|
|||||||
update_output=update_output
|
update_output=update_output
|
||||||
/>
|
/>
|
||||||
<KeyInput set_key_input=set_key_input />
|
<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()>
|
<button class="btn-primary" on:click=move |_| handle_submit()>
|
||||||
{move || format!("{} using {algorithm}", mode.get())}
|
{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]
|
#[component]
|
||||||
fn KeyInput(set_key_input: WriteSignal<String>) -> impl IntoView {
|
fn KeyInput(set_key_input: WriteSignal<String>) -> impl IntoView {
|
||||||
view! {
|
view! {
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="lable-header">
|
<label>"Secret Key"</label>
|
||||||
<label>"Secret Key"</label>
|
|
||||||
<span class="input-hint">"Prefix: 0x (Hex), 0b (Bin), or nothing (Text)"</span>
|
|
||||||
</div>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
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))
|
on:input=move |ev| set_key_input(event_target_value(&ev))
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -206,62 +191,24 @@ fn KeyInput(set_key_input: WriteSignal<String>) -> impl IntoView {
|
|||||||
#[component]
|
#[component]
|
||||||
fn TextInput(
|
fn TextInput(
|
||||||
mode: ReadSignal<OperationMode>,
|
mode: ReadSignal<OperationMode>,
|
||||||
text_input: ReadSignal<String>,
|
|
||||||
set_text_input: WriteSignal<String>,
|
set_text_input: WriteSignal<String>,
|
||||||
) -> impl IntoView {
|
) -> 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! {
|
view! {
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
{move || {
|
<label>
|
||||||
match mode.get() {
|
{move || {
|
||||||
OperationMode::Encrypt => {
|
match mode.get() {
|
||||||
view! {
|
OperationMode::Encrypt => "Plaintext Input",
|
||||||
<div class="lable-header">
|
OperationMode::Decrypt => "Ciphertext (Hex) Input",
|
||||||
<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()
|
|
||||||
}
|
}
|
||||||
OperationMode::Decrypt => {
|
}}
|
||||||
view! {
|
</label>
|
||||||
<div class="lable-header">
|
<input
|
||||||
<label>"Ciphertext Input"</label>
|
type="text"
|
||||||
</div>
|
prop:text_input
|
||||||
<div class="input-wrapper hex-input">
|
placeholder="Enter text..."
|
||||||
<span class="prefix">"0x"</span>
|
on:input=move |ev| set_text_input(event_target_value(&ev))
|
||||||
<input
|
/>
|
||||||
type="text"
|
|
||||||
prop:value=move || text_input.get()
|
|
||||||
placeholder="001122"
|
|
||||||
on:input=handle_hex_input
|
|
||||||
spellcheck="false"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
.into_any()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
</div>
|
</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 {
|
.form-group {
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
|
|
||||||
@ -356,8 +327,15 @@ main {
|
|||||||
|
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
textarea {
|
textarea {
|
||||||
@include input-styles;
|
width: 100%;
|
||||||
padding: 12px;
|
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 {
|
&:focus {
|
||||||
@ -571,7 +549,7 @@ main {
|
|||||||
font-size: 6rem;
|
font-size: 6rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: var(--error);
|
color: var(--error);
|
||||||
font-family: "Consolas", "Monaco", monospace;
|
font-family: "Consolar", "Monaco", monospace;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
@ -606,68 +584,3 @@ main {
|
|||||||
width: auto;
|
width: auto;
|
||||||
text-align: center;
|
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