From 8634167743d9855a4022695052f0e5ecc45010b2 Mon Sep 17 00:00:00 2001 From: Pavlo Myroniuk Date: Sun, 17 Mar 2024 22:52:58 +0200 Subject: [PATCH 1/4] feat(crypto-helper): started implementing non-blocking tasks using worker threads; --- Cargo.lock | 430 ++++++++++++++++++++++++++++++--- Cargo.toml | 1 + public/styles/diff/styles.scss | 2 + src/diff.rs | 40 ++- src/diff/task.rs | 30 +++ 5 files changed, 459 insertions(+), 44 deletions(-) create mode 100644 src/diff/task.rs diff --git a/Cargo.lock b/Cargo.lock index a204e127..9a8f1479 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -481,6 +481,12 @@ dependencies = [ "log", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.8" @@ -541,6 +547,7 @@ checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -563,6 +570,17 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.29" @@ -645,17 +663,36 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28999cda5ef6916ffd33fb4a7b87e1de633c47c0dc6d97905fee1cdaa142b94d" dependencies = [ - "gloo-console", - "gloo-dialogs", - "gloo-events", - "gloo-file", - "gloo-history", - "gloo-net", - "gloo-render", - "gloo-storage", - "gloo-timers", - "gloo-utils", - "gloo-worker", + "gloo-console 0.2.3", + "gloo-dialogs 0.1.1", + "gloo-events 0.1.2", + "gloo-file 0.2.3", + "gloo-history 0.1.5", + "gloo-net 0.3.1", + "gloo-render 0.1.1", + "gloo-storage 0.2.2", + "gloo-timers 0.2.6", + "gloo-utils 0.1.7", + "gloo-worker 0.2.1", +] + +[[package]] +name = "gloo" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd35526c28cc55c1db77aed6296de58677dbab863b118483a27845631d870249" +dependencies = [ + "gloo-console 0.3.0", + "gloo-dialogs 0.2.0", + "gloo-events 0.2.0", + "gloo-file 0.3.0", + "gloo-history 0.2.2", + "gloo-net 0.4.0", + "gloo-render 0.2.0", + "gloo-storage 0.3.0", + "gloo-timers 0.3.0", + "gloo-utils 0.2.0", + "gloo-worker 0.4.0", ] [[package]] @@ -664,7 +701,20 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" dependencies = [ - "gloo-utils", + "gloo-utils 0.1.7", + "js-sys", + "serde", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-console" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a17868f56b4a24f677b17c8cb69958385102fa879418052d60b50bc1727e261" +dependencies = [ + "gloo-utils 0.2.0", "js-sys", "serde", "wasm-bindgen", @@ -681,6 +731,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-dialogs" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4748e10122b01435750ff530095b1217cf6546173459448b83913ebe7815df" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-events" version = "0.1.2" @@ -691,6 +751,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-events" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c26fb45f7c385ba980f5fa87ac677e363949e065a083722697ef1b2cc91e41" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-file" version = "0.2.3" @@ -698,7 +768,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" dependencies = [ "futures-channel", - "gloo-events", + "gloo-events 0.1.2", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-file" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97563d71863fb2824b2e974e754a81d19c4a7ec47b09ced8a0e6656b6d54bd1f" +dependencies = [ + "gloo-events 0.2.0", "js-sys", "wasm-bindgen", "web-sys", @@ -710,10 +792,27 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85725d90bf0ed47063b3930ef28e863658a7905989e9929a8708aab74a1d5e7f" dependencies = [ - "gloo-events", - "gloo-utils", + "gloo-events 0.1.2", + "gloo-utils 0.1.7", + "serde", + "serde-wasm-bindgen 0.5.0", + "serde_urlencoded", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-history" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "903f432be5ba34427eac5e16048ef65604a82061fe93789f2212afc73d8617d6" +dependencies = [ + "getrandom", + "gloo-events 0.2.0", + "gloo-utils 0.2.0", "serde", - "serde-wasm-bindgen", + "serde-wasm-bindgen 0.6.5", "serde_urlencoded", "thiserror", "wasm-bindgen", @@ -729,7 +828,28 @@ dependencies = [ "futures-channel", "futures-core", "futures-sink", - "gloo-utils", + "gloo-utils 0.1.7", + "http", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-net" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ac9e8288ae2c632fa9f8657ac70bfe38a1530f345282d7ba66a1f70b72b7dc4" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils 0.2.0", "http", "js-sys", "pin-project", @@ -751,13 +871,38 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-render" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56008b6744713a8e8d98ac3dcb7d06543d5662358c9c805b4ce2167ad4649833" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-storage" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" dependencies = [ - "gloo-utils", + "gloo-utils 0.1.7", + "js-sys", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-storage" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a" +dependencies = [ + "gloo-utils 0.2.0", "js-sys", "serde", "serde_json", @@ -778,6 +923,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "gloo-utils" version = "0.1.7" @@ -791,6 +946,19 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-worker" version = "0.2.1" @@ -799,15 +967,46 @@ checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a" dependencies = [ "anymap2", "bincode", - "gloo-console", - "gloo-utils", + "gloo-console 0.2.3", + "gloo-utils 0.1.7", + "js-sys", + "serde", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-worker" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76495d3dd87de51da268fa3a593da118ab43eb7f8809e17eb38d3319b424e400" +dependencies = [ + "bincode", + "futures", + "gloo-utils 0.2.0", + "gloo-worker-macros", "js-sys", + "pinned", "serde", + "thiserror", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", ] +[[package]] +name = "gloo-worker-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956caa58d4857bc9941749d55e4bd3000032d8212762586fa5705632967140e7" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.41", +] + [[package]] name = "group" version = "0.12.1" @@ -825,6 +1024,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "hermit-abi" version = "0.3.3" @@ -890,7 +1095,27 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfd6201e7c30ccb24773cac7efa6fec1e06189d414b7439ce756a481c8bfbf53" dependencies = [ - "indexmap", + "indexmap 1.9.3", +] + +[[package]] +name = "implicit-clone" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a9aa791c7b5a71b636b7a68207fdebf171ddfc593d9c8506ec4cbc527b6a84" +dependencies = [ + "implicit-clone-derive", + "indexmap 1.9.3", +] + +[[package]] +name = "implicit-clone-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9311685eb9a34808bbb0608ad2fcab9ae216266beca5848613e95553ac914e3b" +dependencies = [ + "quote", + "syn 2.0.41", ] [[package]] @@ -900,7 +1125,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", ] [[package]] @@ -1427,6 +1662,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.41", +] + [[package]] name = "primeorder" version = "0.12.1" @@ -1436,6 +1681,16 @@ dependencies = [ "elliptic-curve", ] +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1476,7 +1731,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" dependencies = [ "futures", - "gloo", + "gloo 0.8.1", "num_cpus", "once_cell", "pin-project", @@ -1742,6 +1997,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_bytes" version = "0.11.12" @@ -2009,6 +2275,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.2.5", + "toml_datetime", + "winnow", +] + [[package]] name = "tracing" version = "0.1.40" @@ -2187,7 +2470,7 @@ dependencies = [ "base64 0.13.1", "bcrypt", "flate2", - "gloo-timers", + "gloo-timers 0.2.6", "hex", "hmac-sha256", "hmac-sha512", @@ -2210,7 +2493,8 @@ dependencies = [ "wasm-bindgen", "wasm-logger", "web-sys", - "yew", + "yew 0.20.0", + "yew-agent", "yew-hooks", "yew-notifications", "yew-router", @@ -2358,6 +2642,15 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "yew" version = "0.20.0" @@ -2366,9 +2659,34 @@ checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" dependencies = [ "console_error_panic_hook", "futures", - "gloo", - "implicit-clone", - "indexmap", + "gloo 0.8.1", + "implicit-clone 0.3.9", + "indexmap 1.9.3", + "js-sys", + "prokio", + "rustversion", + "serde", + "slab", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "yew-macro 0.20.0", +] + +[[package]] +name = "yew" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f1a03f255c70c7aa3e9c62e15292f142ede0564123543c1cc0c7a4f31660cac" +dependencies = [ + "console_error_panic_hook", + "futures", + "gloo 0.10.0", + "implicit-clone 0.4.9", + "indexmap 2.2.5", "js-sys", "prokio", "rustversion", @@ -2380,7 +2698,32 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "yew-macro", + "yew-macro 0.21.0", +] + +[[package]] +name = "yew-agent" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e27eaca61ea9d0e1a6589dce592283b0e62ced527d8a8b28447957295d588f5" +dependencies = [ + "futures", + "gloo-worker 0.4.0", + "serde", + "wasm-bindgen", + "yew 0.21.0", + "yew-agent-macro", +] + +[[package]] +name = "yew-agent-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ad00f6c9436d25c9225ed0fd8eea27e6d2886c1387bf934afdf91e9131b8b77" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.41", ] [[package]] @@ -2389,14 +2732,14 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "268e2367720311f19582235f5c021702d6be8ded13b7ee8dcacc71019d055d15" dependencies = [ - "gloo", + "gloo 0.8.1", "js-sys", "log", "serde", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "yew", + "yew 0.20.0", ] [[package]] @@ -2407,23 +2750,38 @@ checksum = "b64c253c1d401f1ea868ca9988db63958cfa15a69f739101f338d6f05eea8301" dependencies = [ "boolinator", "once_cell", - "prettyplease", + "prettyplease 0.1.25", "proc-macro-error", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "yew-macro" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fd8ca5166d69e59f796500a2ce432ff751edecbbb308ca59fd3fe4d0343de2" +dependencies = [ + "boolinator", + "once_cell", + "prettyplease 0.2.15", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.41", +] + [[package]] name = "yew-notifications" version = "0.1.0" source = "git+https://github.com/TheBestTvarynka/yew-notifications.git#50d0055dd37c031abd3825237b1a567896526748" dependencies = [ - "gloo", + "gloo 0.8.1", "log", "time", "uuid", - "yew", + "yew 0.20.0", ] [[package]] @@ -2432,7 +2790,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "426ee0486d2572a6c5e39fbdbc48b58d59bb555f3326f54631025266cf04146e" dependencies = [ - "gloo", + "gloo 0.8.1", "js-sys", "route-recognizer", "serde", @@ -2440,7 +2798,7 @@ dependencies = [ "tracing", "wasm-bindgen", "web-sys", - "yew", + "yew 0.20.0", "yew-router-macro", ] diff --git a/Cargo.toml b/Cargo.toml index 069c8313..89af505f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ yew = { version = "0.20", features = ["csr"] } yew-router = "0.17.0" yew-notifications = { git = "https://github.com/TheBestTvarynka/yew-notifications.git", features = ["standard-notification"] } yew-hooks = "0.2.0" +yew-agent = "0.3.0" # wasm js-sys = "0.3.60" diff --git a/public/styles/diff/styles.scss b/public/styles/diff/styles.scss index ef2c1e73..1688760c 100644 --- a/public/styles/diff/styles.scss +++ b/public/styles/diff/styles.scss @@ -33,4 +33,6 @@ background-color: #edd5ce; padding-right: 0.3em; padding-left: 0.3em; + border-bottom: 2px solid #403735; + margin-right: 0.3em; } \ No newline at end of file diff --git a/src/diff.rs b/src/diff.rs index 5cc69ca5..b52f87b3 100644 --- a/src/diff.rs +++ b/src/diff.rs @@ -1,15 +1,20 @@ mod diff_algo; mod diff_viewer; +mod task; +use serde::{Deserialize, Serialize}; use similar::{capture_diff_slices, Algorithm, DiffOp, TextDiff}; use web_sys::{HtmlInputElement, KeyboardEvent}; use yew::html::onchange::Event; +use yew::platform::spawn_local; use yew::virtual_dom::VNode; use yew::{classes, function_component, html, use_effect_with_deps, use_state, Callback, Html, TargetCast}; -use yew_hooks::use_local_storage; +use yew_agent::oneshot::{use_oneshot_runner, OneshotProvider}; +use yew_hooks::{use_async, use_local_storage}; use self::diff_algo::DiffAlgo; use self::diff_viewer::DiffViewer; +use self::task::{DiffTask, DiffTaskParams}; const DEFAULT_ORIGINAL: &str = "TheBestTvarynka TheBestTvarynka @@ -30,7 +35,7 @@ const ALL_ALGORITHMS: &[DiffAlgo] = &[ DiffAlgo(Algorithm::Patience), ]; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] struct DiffData { pub original: Vec, pub changed: Vec, @@ -92,6 +97,23 @@ pub fn diff_page() -> Html { }); }); + let diff_task_params = DiffTaskParams { + original: original.chars().collect::>(), + changed: changed.chars().collect::>(), + algo: *algorithm, + }; + let diffs_setter = diffs.setter(); + let diff_task = use_oneshot_runner::(); + let diffs_worker = { + let diff_agent = diff_task.clone(); + Callback::from(move |_| { + spawn_local(async move { + let diff_data = diff_agent.run(diff_task_params).await; + diffs_setter.set(diff_data); + }); + }) + }; + let original_local_storage = use_local_storage::(LOCAL_STORAGE_ORIGINAL.to_owned()); let original_setter = original.setter(); let changed_local_storage = use_local_storage::(LOCAL_STORAGE_CHANGED.to_owned()); @@ -161,10 +183,12 @@ pub fn diff_page() -> Html { changed_setter.set(input.value()); }); - let diff = compute_diff.clone(); - let onclick = Callback::from(move |_| { - diff.emit(()); - }); + let onclick = { + Callback::from(move |_| { + debug!("started worker thread task"); + diffs_worker.emit(()); + }) + }; let algorithm_setter = algorithm.setter(); let on_algorithm_change = Callback::from(move |event: Event| { @@ -181,7 +205,7 @@ pub fn diff_page() -> Html { }); html! { -
+ path="/worker.js" class={classes!("vertical", "asn1-page")} {onkeydown}>
{"Diff algorithm:"}
@@ -213,6 +237,6 @@ pub fn diff_page() -> Html { {"(ctrl+enter)"}
-
+
> } } diff --git a/src/diff/task.rs b/src/diff/task.rs new file mode 100644 index 00000000..a7af9914 --- /dev/null +++ b/src/diff/task.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; +use similar::capture_diff_slices; +use yew_agent::oneshot::oneshot; + +use crate::diff::diff_algo::DiffAlgo; +use crate::diff::DiffData; + +#[derive(Serialize, Deserialize)] +pub struct DiffTaskParams { + pub algo: DiffAlgo, + pub original: Vec, + pub changed: Vec, +} + +#[oneshot] +pub async fn DiffTask(params: DiffTaskParams) -> DiffData { + let DiffTaskParams { + algo, + original, + changed, + } = params; + + let changes = capture_diff_slices(algo.into(), &original, &changed); + + DiffData { + original, + changed, + changes, + } +} From 8bb2034dee1e96a35930de62dad87e6a90eddf37 Mon Sep 17 00:00:00 2001 From: Pavlo Myroniuk Date: Mon, 18 Mar 2024 01:31:20 +0200 Subject: [PATCH 2/4] feat(crypto-helper): diff: set up worker properly; * create `main` and `worker` bins. registered them in `Cargo.toml` and `index.html`; * set up woker context properly; * implement needed methods for serialization and deserealization. *TODO*: *fix* _"can't deserialize an worker message: DeserializeAnyNotSupported"_ error. --- Cargo.lock | 79 +++++++++++++++++++++-------------------- Cargo.toml | 12 +++++-- index.html | 5 +++ src/bin/main.rs | 7 ++++ src/bin/worker.rs | 8 +++++ src/diff.rs | 20 +++++++---- src/diff/diff_algo.rs | 39 +++++++++++++++++++- src/diff/task.rs | 6 +++- src/{main.rs => lib.rs} | 17 ++++----- 9 files changed, 136 insertions(+), 57 deletions(-) create mode 100644 src/bin/main.rs create mode 100644 src/bin/worker.rs rename src/{main.rs => lib.rs} (87%) diff --git a/Cargo.lock b/Cargo.lock index 3ca17b2e..0ed3fabf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -379,6 +379,44 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "crypto-helper" +version = "0.10.0" +dependencies = [ + "asn1-parser", + "base64 0.22.0", + "bcrypt", + "flate2", + "gloo-timers 0.3.0", + "hex", + "hmac-sha256", + "hmac-sha512", + "js-sys", + "log", + "md5", + "oid", + "paste", + "picky", + "picky-krb", + "rand 0.9.0-alpha.0", + "rand_chacha 0.9.0-alpha.0", + "rsa", + "serde", + "serde_json", + "serde_qs", + "sha1 0.11.0-pre.3", + "similar", + "time", + "wasm-bindgen", + "wasm-logger", + "web-sys", + "yew", + "yew-agent", + "yew-hooks", + "yew-notifications", + "yew-router", +] + [[package]] name = "curve25519-dalek" version = "4.1.2" @@ -2217,6 +2255,9 @@ name = "similar" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" +dependencies = [ + "serde", +] [[package]] name = "slab" @@ -2544,44 +2585,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "web-app" -version = "0.10.0" -dependencies = [ - "asn1-parser", - "base64 0.22.0", - "bcrypt", - "flate2", - "gloo-timers 0.3.0", - "hex", - "hmac-sha256", - "hmac-sha512", - "js-sys", - "log", - "md5", - "oid", - "paste", - "picky", - "picky-krb", - "rand 0.9.0-alpha.0", - "rand_chacha 0.9.0-alpha.0", - "rsa", - "serde", - "serde_json", - "serde_qs", - "sha1 0.11.0-pre.3", - "similar", - "time", - "wasm-bindgen", - "wasm-logger", - "web-sys", - "yew", - "yew-agent", - "yew-hooks", - "yew-notifications", - "yew-router", -] - [[package]] name = "web-sys" version = "0.3.69" diff --git a/Cargo.toml b/Cargo.toml index 046d5faf..eff6de25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "web-app" +name = "crypto-helper" version = "0.10.0" description = "The crypto-helper is an online app that helps to work with the diferent crypto algorithms." edition = "2021" @@ -14,6 +14,14 @@ members = [ "crates/prop-strategies" ] +[[bin]] +name = "crypto-helper-app" +path = "src/bin/main.rs" + +[[bin]] +name = "worker" +path = "src/bin/worker.rs" + [dependencies] yew = { version = "0.21", features = ["csr"] } yew-router = "0.18" @@ -58,4 +66,4 @@ oid = { version = "0.2", default-features = false } paste = "1.0" # diff -similar = "2.4" \ No newline at end of file +similar = { version = "2.4", features = ["serde"] } \ No newline at end of file diff --git a/index.html b/index.html index 878295b5..01fc53ea 100644 --- a/index.html +++ b/index.html @@ -3,6 +3,7 @@ Crypto helper + @@ -32,5 +33,9 @@ + + + + \ No newline at end of file diff --git a/src/bin/main.rs b/src/bin/main.rs new file mode 100644 index 00000000..bfdf0d8d --- /dev/null +++ b/src/bin/main.rs @@ -0,0 +1,7 @@ +use crypto_helper::App; + +fn main() { + wasm_logger::init(wasm_logger::Config::default()); + + yew::Renderer::::new().render(); +} diff --git a/src/bin/worker.rs b/src/bin/worker.rs new file mode 100644 index 00000000..cbff2da4 --- /dev/null +++ b/src/bin/worker.rs @@ -0,0 +1,8 @@ +use crypto_helper::diff::DiffTask; +use yew_agent::{Bincode, Registrable}; + +fn main() { + wasm_logger::init(wasm_logger::Config::default()); + + DiffTask::registrar().encoding::().register(); +} diff --git a/src/diff.rs b/src/diff.rs index 26ae7790..c770ff36 100644 --- a/src/diff.rs +++ b/src/diff.rs @@ -8,13 +8,13 @@ use web_sys::{HtmlInputElement, KeyboardEvent}; use yew::html::onchange::Event; use yew::platform::spawn_local; use yew::virtual_dom::VNode; +use yew::{function_component, html, use_effect_with, use_state, Callback, Html, TargetCast}; use yew_agent::oneshot::{use_oneshot_runner, OneshotProvider}; -use yew::{classes, function_component, html, use_effect_with, use_state, Callback, Html, TargetCast}; -use yew_hooks::{use_async, use_local_storage}; +use yew_hooks::use_local_storage; use self::diff_algo::DiffAlgo; use self::diff_viewer::DiffViewer; -use self::task::{DiffTask, DiffTaskParams}; +pub use self::task::{DiffTask, DiffTaskParams}; const DEFAULT_ORIGINAL: &str = "TheBestTvarynka TheBestTvarynka @@ -36,7 +36,7 @@ const ALL_ALGORITHMS: &[DiffAlgo] = &[ ]; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -struct DiffData { +pub struct DiffData { pub original: Vec, pub changed: Vec, pub changes: Vec, @@ -105,11 +105,17 @@ pub fn diff_page() -> Html { let diffs_setter = diffs.setter(); let diff_task = use_oneshot_runner::(); let diffs_worker = { - let diff_agent = diff_task.clone(); Callback::from(move |_| { + let diff_agent = diff_task.clone(); + let diff_task_params = diff_task_params.clone(); + let diffs_setter = diffs_setter.clone(); + spawn_local(async move { + debug!("started worker as async task"); let diff_data = diff_agent.run(diff_task_params).await; + debug!("finished calculation"); diffs_setter.set(diff_data); + debug!("data has been set!"); }); }) }; @@ -193,7 +199,7 @@ pub fn diff_page() -> Html { }); html! { - path="/worker.js" class={classes!("vertical", "asn1-page")} {onkeydown}> +
{"Diff algorithm:"}
@@ -225,6 +231,6 @@ pub fn diff_page() -> Html { {"(ctrl+enter)"}
- > +
} } diff --git a/src/diff/diff_algo.rs b/src/diff/diff_algo.rs index e888f94f..2c278807 100644 --- a/src/diff/diff_algo.rs +++ b/src/diff/diff_algo.rs @@ -1,13 +1,15 @@ use std::fmt::{Display, Formatter}; use std::ops::Deref; +use serde::de::{Error, Visitor}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use similar::Algorithm; const MYERS: &str = "Myers"; const PATIENCE: &str = "Patience"; const LCS: &str = "Lcs"; -#[derive(Clone, Copy, Eq, PartialEq)] +#[derive(Clone, Copy, Eq, PartialEq, Debug)] pub struct DiffAlgo(pub Algorithm); impl From for Algorithm { @@ -58,3 +60,38 @@ impl TryFrom<&str> for DiffAlgo { }) } } + +impl<'de> Deserialize<'de> for DiffAlgo { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct DiffAlgoVisitor; + + impl Visitor<'_> for DiffAlgoVisitor { + type Value = DiffAlgo; + + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("valid DiffAlgo") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + DiffAlgo::try_from(v).map_err(|err| E::custom(format!("Can not deserialize DiffAlgo: {:?}", err))) + } + } + + deserializer.deserialize_str(DiffAlgoVisitor) + } +} + +impl Serialize for DiffAlgo { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self.as_ref()) + } +} diff --git a/src/diff/task.rs b/src/diff/task.rs index a7af9914..8e068675 100644 --- a/src/diff/task.rs +++ b/src/diff/task.rs @@ -5,7 +5,7 @@ use yew_agent::oneshot::oneshot; use crate::diff::diff_algo::DiffAlgo; use crate::diff::DiffData; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] pub struct DiffTaskParams { pub algo: DiffAlgo, pub original: Vec, @@ -14,6 +14,8 @@ pub struct DiffTaskParams { #[oneshot] pub async fn DiffTask(params: DiffTaskParams) -> DiffData { + debug!("inside of the task: {:?}", params); + let DiffTaskParams { algo, original, @@ -22,6 +24,8 @@ pub async fn DiffTask(params: DiffTaskParams) -> DiffData { let changes = capture_diff_slices(algo.into(), &original, &changed); + debug!("changes here"); + DiffData { original, changed, diff --git a/src/main.rs b/src/lib.rs similarity index 87% rename from src/main.rs rename to src/lib.rs index 506df233..fcf1821b 100644 --- a/src/main.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ mod about; mod asn1; mod common; mod crypto_helper; -mod diff; +pub mod diff; mod footer; mod header; mod jwt; @@ -23,9 +23,12 @@ use header::Header; use jwt::Jwt; use not_found::not_found; use yew::{function_component, html, Html}; +use yew_agent::oneshot::OneshotProvider; use yew_notifications::{Notification, NotificationFactory, NotificationsProvider}; use yew_router::{BrowserRouter, Routable, Switch}; +use crate::diff::DiffTask; + #[derive(Clone, Routable, PartialEq)] enum Route { #[at("/")] @@ -51,7 +54,11 @@ fn switch(routes: Route) -> Html { Route::Asn1Parser => html! { }, Route::CryptoHelper => html! { }, Route::Jwt => html! { }, - Route::Diff => html! { }, + Route::Diff => html! { + path="worker.js"> + + > + }, Route::About => html! { }, Route::NotFound => not_found(), } @@ -73,9 +80,3 @@ pub fn app() -> Html { } } - -fn main() { - wasm_logger::init(wasm_logger::Config::default()); - - yew::Renderer::::new().render(); -} From 484212d7d742e6238db36982f66a7866072d2ce8 Mon Sep 17 00:00:00 2001 From: Pavlo Myroniuk Date: Mon, 18 Mar 2024 21:02:55 +0200 Subject: [PATCH 3/4] feat(crypto-helper): diff: use custom codec for communication with worker; With the default `Bincode` codec we have got the `DeserializeAnyNotSupported` error. The custom codec uses `serde_json` to encoded and decode messages. --- src/bin/worker.rs | 6 ++--- src/diff.rs | 62 ++++++++++++++++++++++------------------------- src/diff/task.rs | 30 ++++++++++++++++++++--- src/lib.rs | 7 +++--- 4 files changed, 62 insertions(+), 43 deletions(-) diff --git a/src/bin/worker.rs b/src/bin/worker.rs index cbff2da4..b8cf3765 100644 --- a/src/bin/worker.rs +++ b/src/bin/worker.rs @@ -1,8 +1,8 @@ -use crypto_helper::diff::DiffTask; -use yew_agent::{Bincode, Registrable}; +use crypto_helper::diff::{DiffTask, JsonCodec}; +use yew_agent::Registrable; fn main() { wasm_logger::init(wasm_logger::Config::default()); - DiffTask::registrar().encoding::().register(); + DiffTask::registrar().encoding::().register(); } diff --git a/src/diff.rs b/src/diff.rs index c770ff36..d77350e3 100644 --- a/src/diff.rs +++ b/src/diff.rs @@ -3,18 +3,18 @@ mod diff_viewer; mod task; use serde::{Deserialize, Serialize}; -use similar::{capture_diff_slices, Algorithm, DiffOp, TextDiff}; +use similar::{Algorithm, DiffOp, TextDiff}; use web_sys::{HtmlInputElement, KeyboardEvent}; use yew::html::onchange::Event; use yew::platform::spawn_local; use yew::virtual_dom::VNode; -use yew::{function_component, html, use_effect_with, use_state, Callback, Html, TargetCast}; -use yew_agent::oneshot::{use_oneshot_runner, OneshotProvider}; +use yew::{function_component, html, use_effect_with, use_state_eq, Callback, Html, TargetCast}; +use yew_agent::oneshot::use_oneshot_runner; use yew_hooks::use_local_storage; use self::diff_algo::DiffAlgo; use self::diff_viewer::DiffViewer; -pub use self::task::{DiffTask, DiffTaskParams}; +pub use self::task::{DiffTask, DiffTaskParams, JsonCodec}; const DEFAULT_ORIGINAL: &str = "TheBestTvarynka TheBestTvarynka @@ -35,7 +35,7 @@ const ALL_ALGORITHMS: &[DiffAlgo] = &[ DiffAlgo(Algorithm::Patience), ]; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct DiffData { pub original: Vec, pub changed: Vec, @@ -52,6 +52,13 @@ impl DiffData { } } +#[derive(Debug, Clone, PartialEq, Eq)] +enum DiffsState { + None, + Loading, + Diffs(DiffData), +} + fn render_algorithm_options(current_algorithm: DiffAlgo) -> Vec { ALL_ALGORITHMS .iter() @@ -65,10 +72,10 @@ fn render_algorithm_options(current_algorithm: DiffAlgo) -> Vec { #[function_component(DiffPage)] pub fn diff_page() -> Html { - let original = use_state(|| DEFAULT_ORIGINAL.to_owned()); - let changed = use_state(|| DEFAULT_CHANGED.to_owned()); - let algorithm = use_state(|| DEFAULT_ALGORITHM); - let diffs = use_state(|| { + let original = use_state_eq(|| DEFAULT_ORIGINAL.to_owned()); + let changed = use_state_eq(|| DEFAULT_CHANGED.to_owned()); + let algorithm = use_state_eq(|| DEFAULT_ALGORITHM); + let diffs = use_state_eq(|| { let original = DEFAULT_ORIGINAL.chars().collect::>(); let changed = DEFAULT_CHANGED.chars().collect::>(); let changes = TextDiff::configure() @@ -76,25 +83,11 @@ pub fn diff_page() -> Html { .newline_terminated(true) .diff_chars(DEFAULT_ORIGINAL, DEFAULT_CHANGED); - DiffData { + DiffsState::Diffs(DiffData { original, changed, changes: changes.ops().to_owned(), - } - }); - - let original_data = original.chars().collect::>(); - let changed_data = changed.chars().collect::>(); - let diffs_setter = diffs.setter(); - let algo = *algorithm; - let compute_diff = Callback::from(move |_: ()| { - let changes = capture_diff_slices(algo.into(), &original_data, &changed_data); - - diffs_setter.set(DiffData { - original: original_data.clone(), - changed: changed_data.clone(), - changes, - }); + }) }); let diff_task_params = DiffTaskParams { @@ -106,16 +99,15 @@ pub fn diff_page() -> Html { let diff_task = use_oneshot_runner::(); let diffs_worker = { Callback::from(move |_| { + diffs_setter.set(DiffsState::Loading); + let diff_agent = diff_task.clone(); let diff_task_params = diff_task_params.clone(); let diffs_setter = diffs_setter.clone(); spawn_local(async move { - debug!("started worker as async task"); let diff_data = diff_agent.run(diff_task_params).await; - debug!("finished calculation"); - diffs_setter.set(diff_data); - debug!("data has been set!"); + diffs_setter.set(DiffsState::Diffs(diff_data)); }); }) }; @@ -146,7 +138,7 @@ pub fn diff_page() -> Html { } if flag { - diffs_setter.set(DiffData::empty()); + diffs_setter.set(DiffsState::None); } }); @@ -178,8 +170,8 @@ pub fn diff_page() -> Html { }); let onclick = { + let diffs_worker = diffs_worker.clone(); Callback::from(move |_| { - debug!("started worker thread task"); diffs_worker.emit(()); }) }; @@ -194,7 +186,7 @@ pub fn diff_page() -> Html { let onkeydown = Callback::from(move |event: KeyboardEvent| { if event.ctrl_key() && event.code() == "Enter" { - compute_diff.emit(()); + diffs_worker.emit(()); } }); @@ -230,7 +222,11 @@ pub fn diff_page() -> Html { {"(ctrl+enter)"}
- + {match (*diffs).clone() { + DiffsState::None => html! {}, + DiffsState::Loading => html! { {"Loading"} }, + DiffsState::Diffs(diff) => html! { }, + }}
} } diff --git a/src/diff/task.rs b/src/diff/task.rs index 8e068675..8ba2e6f6 100644 --- a/src/diff/task.rs +++ b/src/diff/task.rs @@ -1,10 +1,36 @@ +use js_sys::Uint8Array; use serde::{Deserialize, Serialize}; use similar::capture_diff_slices; +use wasm_bindgen::{JsCast, JsValue}; use yew_agent::oneshot::oneshot; +use yew_agent::Codec; use crate::diff::diff_algo::DiffAlgo; use crate::diff::DiffData; +/// Codes for messages encoding/decoding between main thread and worker. +/// +/// We are using the custom codec because default `Bincode` fails to decode [DiffData]. +pub struct JsonCodec; + +impl Codec for JsonCodec { + fn encode(input: I) -> JsValue + where + I: Serialize, + { + let encoded = serde_json::to_string(&input).expect("Json serialization should not fail"); + JsValue::from(Uint8Array::from(encoded.as_bytes())) + } + + fn decode(input: JsValue) -> O + where + O: for<'de> Deserialize<'de>, + { + let encoded = input.dyn_into::().expect("JsValue should be Uint8Array"); + serde_json::from_slice(&encoded.to_vec()).expect("Json deserialization should not fail") + } +} + #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] pub struct DiffTaskParams { pub algo: DiffAlgo, @@ -14,8 +40,6 @@ pub struct DiffTaskParams { #[oneshot] pub async fn DiffTask(params: DiffTaskParams) -> DiffData { - debug!("inside of the task: {:?}", params); - let DiffTaskParams { algo, original, @@ -24,8 +48,6 @@ pub async fn DiffTask(params: DiffTaskParams) -> DiffData { let changes = capture_diff_slices(algo.into(), &original, &changed); - debug!("changes here"); - DiffData { original, changed, diff --git a/src/lib.rs b/src/lib.rs index fcf1821b..20c6c44f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ use yew_agent::oneshot::OneshotProvider; use yew_notifications::{Notification, NotificationFactory, NotificationsProvider}; use yew_router::{BrowserRouter, Routable, Switch}; -use crate::diff::DiffTask; +use crate::diff::{DiffTask, JsonCodec}; #[derive(Clone, Routable, PartialEq)] enum Route { @@ -55,9 +55,10 @@ fn switch(routes: Route) -> Html { Route::CryptoHelper => html! { }, Route::Jwt => html! { }, Route::Diff => html! { - path="worker.js"> + // worker.js - will be autogenerated and placed in the root of the destination directory. + path="worker.js"> - > + > }, Route::About => html! { }, Route::NotFound => not_found(), From 78179bdf752977c8342b6e1585a9ca46839f321a Mon Sep 17 00:00:00 2001 From: Pavlo Myroniuk Date: Mon, 18 Mar 2024 21:20:03 +0200 Subject: [PATCH 4/4] feat(crypto-helper): add simple `Loader` component (spinner); --- public/styles/style.scss | 89 ++++++++++++++++++++++++++++++++++++++++ src/common/loader.rs | 10 +++++ src/common/mod.rs | 2 + src/diff.rs | 3 +- 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/common/loader.rs diff --git a/public/styles/style.scss b/public/styles/style.scss index 9a2cbf09..ea5e6ff1 100644 --- a/public/styles/style.scss +++ b/public/styles/style.scss @@ -212,3 +212,92 @@ article { color: #dbcfbf; cursor: pointer; } + +.loader-wrapper { + margin-top: 1em; + margin-bottom: 1em; + width: 100%; + display: inline-flex; +} + +.loader { + color: #322a50; + font-size: 25px; + overflow: hidden; + width: 1em; + height: 1em; + border-radius: 50%; + margin: auto; + -webkit-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); + -webkit-animation: load6 1.3s infinite ease, round 1.3s infinite ease; + animation: load6 1.3s infinite ease, round 1.3s infinite ease; +} +@-webkit-keyframes load6 { + 0% { + box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; + } + 5%, + 95% { + box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; + } + 10%, + 59% { + box-shadow: 0 -0.83em 0 -0.4em, -0.087em -0.825em 0 -0.42em, -0.173em -0.812em 0 -0.44em, -0.256em -0.789em 0 -0.46em, -0.297em -0.775em 0 -0.477em; + } + 20% { + box-shadow: 0 -0.83em 0 -0.4em, -0.338em -0.758em 0 -0.42em, -0.555em -0.617em 0 -0.44em, -0.671em -0.488em 0 -0.46em, -0.749em -0.34em 0 -0.477em; + } + 38% { + box-shadow: 0 -0.83em 0 -0.4em, -0.377em -0.74em 0 -0.42em, -0.645em -0.522em 0 -0.44em, -0.775em -0.297em 0 -0.46em, -0.82em -0.09em 0 -0.477em; + } + 100% { + box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; + } +} + +@keyframes load6 { + 0% { + box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; + } + 5%, + 95% { + box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; + } + 10%, + 59% { + box-shadow: 0 -0.83em 0 -0.4em, -0.087em -0.825em 0 -0.42em, -0.173em -0.812em 0 -0.44em, -0.256em -0.789em 0 -0.46em, -0.297em -0.775em 0 -0.477em; + } + 20% { + box-shadow: 0 -0.83em 0 -0.4em, -0.338em -0.758em 0 -0.42em, -0.555em -0.617em 0 -0.44em, -0.671em -0.488em 0 -0.46em, -0.749em -0.34em 0 -0.477em; + } + 38% { + box-shadow: 0 -0.83em 0 -0.4em, -0.377em -0.74em 0 -0.42em, -0.645em -0.522em 0 -0.44em, -0.775em -0.297em 0 -0.46em, -0.82em -0.09em 0 -0.477em; + } + 100% { + box-shadow: 0 -0.83em 0 -0.4em, 0 -0.83em 0 -0.42em, 0 -0.83em 0 -0.44em, 0 -0.83em 0 -0.46em, 0 -0.83em 0 -0.477em; + } +} + +@-webkit-keyframes round { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes round { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +}; diff --git a/src/common/loader.rs b/src/common/loader.rs new file mode 100644 index 00000000..ff7258f9 --- /dev/null +++ b/src/common/loader.rs @@ -0,0 +1,10 @@ +use yew::{function_component, html, Html}; + +#[function_component(Loader)] +pub fn loader() -> Html { + html! { +
+
+
+ } +} diff --git a/src/common/mod.rs b/src/common/mod.rs index efbff582..faf59ec6 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,6 +1,7 @@ mod byte_input; mod bytes_viewer; mod checkbox; +mod loader; mod rc_slice; mod simple_output; mod switch; @@ -9,6 +10,7 @@ mod table; use base64::Engine; pub use byte_input::{build_byte_input, ByteInput}; pub use checkbox::Checkbox; +pub use loader::Loader; pub use rc_slice::RcSlice; pub use simple_output::build_simple_output; pub use switch::Switch; diff --git a/src/diff.rs b/src/diff.rs index d77350e3..2f9568da 100644 --- a/src/diff.rs +++ b/src/diff.rs @@ -15,6 +15,7 @@ use yew_hooks::use_local_storage; use self::diff_algo::DiffAlgo; use self::diff_viewer::DiffViewer; pub use self::task::{DiffTask, DiffTaskParams, JsonCodec}; +use crate::common::Loader; const DEFAULT_ORIGINAL: &str = "TheBestTvarynka TheBestTvarynka @@ -224,7 +225,7 @@ pub fn diff_page() -> Html {
{match (*diffs).clone() { DiffsState::None => html! {}, - DiffsState::Loading => html! { {"Loading"} }, + DiffsState::Loading => html! { }, DiffsState::Diffs(diff) => html! { }, }}