From f462f2b730033714d98237af3767fc1ccd6de037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin?= <94377405+kevin-legion@users.noreply.github.com> Date: Tue, 21 Jun 2022 16:43:05 -0400 Subject: [PATCH] Editor GUI: Experiments with Yew --- Cargo.lock | 64 +- Cargo.toml | 3 +- .../src/rust/templates/lib.rs.jinja | 2 +- crates/lgn-editor-gui/.gitignore | 2 + crates/lgn-editor-gui/Cargo.lock | 1615 +++++++++++++++++ crates/lgn-editor-gui/Cargo.toml | 45 + crates/lgn-editor-gui/index.html | 42 + crates/lgn-editor-gui/src/errors.rs | 21 + crates/lgn-editor-gui/src/main.rs | 82 + .../src/sycamore/components/app.rs | 70 + .../src/sycamore/components/layout.rs | 12 + .../src/sycamore/components/mod.rs | 3 + .../sycamore/components/resource_browser.rs | 35 + .../lgn-editor-gui/src/sycamore/hooks/mod.rs | 79 + crates/lgn-editor-gui/src/sycamore/mod.rs | 2 + crates/lgn-editor-gui/src/types.rs | 150 ++ crates/lgn-editor-gui/src/utils/auth.rs | 185 ++ crates/lgn-editor-gui/src/utils/dom.rs | 83 + crates/lgn-editor-gui/src/utils/mod.rs | 4 + crates/lgn-editor-gui/src/utils/pkce.rs | 44 + crates/lgn-editor-gui/src/utils/tree.rs | 352 ++++ .../lgn-editor-gui/src/yew/components/app.rs | 68 + .../src/yew/components/layout.rs | 12 + .../lgn-editor-gui/src/yew/components/mod.rs | 3 + .../src/yew/components/resource_browser.rs | 100 + crates/lgn-editor-gui/src/yew/contexts/mod.rs | 2 + .../src/yew/contexts/resources.rs | 29 + .../lgn-editor-gui/src/yew/contexts/todos.rs | 29 + crates/lgn-editor-gui/src/yew/hooks/mod.rs | 86 + crates/lgn-editor-gui/src/yew/mod.rs | 3 + 30 files changed, 3189 insertions(+), 38 deletions(-) create mode 100644 crates/lgn-editor-gui/.gitignore create mode 100644 crates/lgn-editor-gui/Cargo.lock create mode 100644 crates/lgn-editor-gui/Cargo.toml create mode 100644 crates/lgn-editor-gui/index.html create mode 100644 crates/lgn-editor-gui/src/errors.rs create mode 100644 crates/lgn-editor-gui/src/main.rs create mode 100644 crates/lgn-editor-gui/src/sycamore/components/app.rs create mode 100644 crates/lgn-editor-gui/src/sycamore/components/layout.rs create mode 100644 crates/lgn-editor-gui/src/sycamore/components/mod.rs create mode 100644 crates/lgn-editor-gui/src/sycamore/components/resource_browser.rs create mode 100644 crates/lgn-editor-gui/src/sycamore/hooks/mod.rs create mode 100644 crates/lgn-editor-gui/src/sycamore/mod.rs create mode 100644 crates/lgn-editor-gui/src/types.rs create mode 100644 crates/lgn-editor-gui/src/utils/auth.rs create mode 100644 crates/lgn-editor-gui/src/utils/dom.rs create mode 100644 crates/lgn-editor-gui/src/utils/mod.rs create mode 100644 crates/lgn-editor-gui/src/utils/pkce.rs create mode 100644 crates/lgn-editor-gui/src/utils/tree.rs create mode 100644 crates/lgn-editor-gui/src/yew/components/app.rs create mode 100644 crates/lgn-editor-gui/src/yew/components/layout.rs create mode 100644 crates/lgn-editor-gui/src/yew/components/mod.rs create mode 100644 crates/lgn-editor-gui/src/yew/components/resource_browser.rs create mode 100644 crates/lgn-editor-gui/src/yew/contexts/mod.rs create mode 100644 crates/lgn-editor-gui/src/yew/contexts/resources.rs create mode 100644 crates/lgn-editor-gui/src/yew/contexts/todos.rs create mode 100644 crates/lgn-editor-gui/src/yew/hooks/mod.rs create mode 100644 crates/lgn-editor-gui/src/yew/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 9363ccbe5c..63e0329740 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -848,9 +848,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.5.7" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc47084705629d09d15060d70a8dbfce479c842303d05929ce29c74c995916ae" +checksum = "33d590cacd53140ff87cc2e192eb22fc3dc23c5b3f93b0d4f020677f98e8c629" dependencies = [ "async-trait", "axum-core", @@ -879,9 +879,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2efed1c501becea07ce48118786ebcf229531d0d3b28edf224a720020d9e106" +checksum = "cf4d047478b986f14a13edad31a009e2e05cb241f9805d0d75e4cba4e129ad4d" dependencies = [ "async-trait", "bytes", @@ -3439,9 +3439,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.18" +version = "0.14.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" dependencies = [ "bytes", "futures-channel", @@ -3771,9 +3771,9 @@ checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" [[package]] name = "js-sys" -version = "0.3.57" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" dependencies = [ "wasm-bindgen", ] @@ -7379,9 +7379,9 @@ checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" [[package]] name = "reqwest" -version = "0.11.10" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb" +checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" dependencies = [ "base64 0.13.0", "bytes", @@ -7403,14 +7403,15 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls 0.20.2", - "rustls-pemfile 0.3.0", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", "tokio-native-tls", "tokio-rustls 0.23.4", - "tokio-util 0.6.10", + "tokio-util 0.7.2", + "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", @@ -7738,20 +7739,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.0", + "rustls-pemfile", "schannel", "security-framework", ] -[[package]] -name = "rustls-pemfile" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee86d63972a7c661d1536fefe8c3c8407321c3df668891286de28abcd087360" -dependencies = [ - "base64 0.13.0", -] - [[package]] name = "rustls-pemfile" version = "1.0.0" @@ -9530,9 +9522,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -9540,9 +9532,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" dependencies = [ "bumpalo", "lazy_static", @@ -9555,9 +9547,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" +checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -9567,9 +9559,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -9577,9 +9569,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" dependencies = [ "proc-macro2", "quote", @@ -9590,9 +9582,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" [[package]] name = "wayland-client" @@ -9668,9 +9660,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.57" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 67edb3e52d..7e40ead84c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,4 @@ [workspace] members = ["crates/*", "examples/*", "tests/*", "build/*"] -exclude = ["build/env"] +# Editor gui is excluded because of https://github.com/tkaitchuck/aHash/issues/95 +exclude = ["build/env", "crates/lgn-editor-gui"] diff --git a/crates/lgn-api-codegen/src/rust/templates/lib.rs.jinja b/crates/lgn-api-codegen/src/rust/templates/lib.rs.jinja index cf50bb52f5..abce8d7832 100644 --- a/crates/lgn-api-codegen/src/rust/templates/lib.rs.jinja +++ b/crates/lgn-api-codegen/src/rust/templates/lib.rs.jinja @@ -21,4 +21,4 @@ pub fn register_routes< let router = {{ module_path|fmt_module_path }}::server::register_routes(router, server.clone()); {% endif %} {% endfor %} -} +} \ No newline at end of file diff --git a/crates/lgn-editor-gui/.gitignore b/crates/lgn-editor-gui/.gitignore new file mode 100644 index 0000000000..8b84bc46ea --- /dev/null +++ b/crates/lgn-editor-gui/.gitignore @@ -0,0 +1,2 @@ +/dist +/target diff --git a/crates/lgn-editor-gui/Cargo.lock b/crates/lgn-editor-gui/Cargo.lock new file mode 100644 index 0000000000..c5de2015e0 --- /dev/null +++ b/crates/lgn-editor-gui/Cargo.lock @@ -0,0 +1,1615 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "anymap2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" + +[[package]] +name = "async-trait" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "boolinator" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" +dependencies = [ + "log", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gloo" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e691526c3972d1fda35453f6df29925edea014dc75a2dede7661527e9439f0" +dependencies = [ + "gloo-console", + "gloo-dialogs", + "gloo-events", + "gloo-file", + "gloo-history", + "gloo-net", + "gloo-render", + "gloo-storage", + "gloo-timers", + "gloo-utils", + "gloo-worker", +] + +[[package]] +name = "gloo-console" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3907f786f65bbb4f419e918b0c5674175ef1c231ecda93b2dbd65fd1e8882637" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-dialogs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-events" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-file" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa5d6084efa4a2b182ef3a8649cb6506cb4843f22cf907c6e0a799944248ae90" +dependencies = [ + "gloo-events", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-history" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81af52c0d31e86242eecefe1ed4d066deb79cfb80f9f7da0847fac417396bfe" +dependencies = [ + "gloo-events", + "gloo-utils", + "serde", + "serde-wasm-bindgen", + "serde_urlencoded", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-net" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d37f728c2b2b8c568bd2efb34ce9087e347c182db68f101a969b4fe23054d5" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-render" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-storage" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1caa4ba51c99de680dee3ad99c32ca45e9f13311be72079154d222c3f9a6b6f5" +dependencies = [ + "gloo-utils", + "js-sys", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-timers" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-utils" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0bbef55e98d946adbd89f3c65a497cf9adb995a73b99573f30180e8813ab21" +dependencies = [ + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-worker" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c843b9a46d07485026f030be7bd008580a12a2920fea837745a440a3b0c97cb" +dependencies = [ + "anymap2", + "bincode", + "gloo-console", + "gloo-utils", + "js-sys", + "serde", + "slab", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "h2" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" + +[[package]] +name = "html-escape" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e7479fa1ef38eb49fb6a42c426be515df2d063f06cb8efd3e50af073dbc26c" +dependencies = [ + "utf8-width", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c6392766afd7964e2531940894cffe4bd8d7d17dbc3c1c4857040fd4b33bdb3" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "ipnet" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "js-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lgn-editor-gui" +version = "0.1.0" +dependencies = [ + "async-trait", + "base64", + "console_log", + "getrandom", + "gloo-storage", + "log", + "rand", + "reqwest", + "serde", + "serde_json", + "sha2", + "sycamore", + "thiserror", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wee_alloc", + "yew", +] + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mio" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "once_cell" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + +[[package]] +name = "openssl" +version = "0.10.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "paste" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "prettyplease" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5355b9d4fc0cc607db0c2e93c7a035a32226bfa770e0c6fec504f0018015bad" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] + +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "618365e8e586c22123d692b72a7d791d5ee697817b65a218cdf12a98870af0f7" +dependencies = [ + "fnv", + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "sycamore" +version = "0.8.0-beta.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3fad8d7500e6f00f7415f3f3b4d7c465b9edce7eaa9f2d725ced0f99fae3c2" +dependencies = [ + "ahash", + "futures", + "indexmap", + "js-sys", + "paste", + "sycamore-core", + "sycamore-futures", + "sycamore-macro", + "sycamore-reactive", + "sycamore-web", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "sycamore-core" +version = "0.8.0-beta.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e3f2be6d4d8aaaae4ab9e7ce3414555dfb0675dfd5b02d733a57f448578f48d" +dependencies = [ + "ahash", + "sycamore-reactive", +] + +[[package]] +name = "sycamore-futures" +version = "0.8.0-beta.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faebade534e638217448ebc6b4cc7a52471ce055a04090e9e628e783bf629e4e" +dependencies = [ + "futures", + "sycamore-reactive", + "tokio", + "wasm-bindgen-futures", +] + +[[package]] +name = "sycamore-macro" +version = "0.8.0-beta.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6ece3ca423f48a9cb6e8a63478c83553cd4dc934de6f1aeb4b5ddb5d3e4cc2" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sycamore-reactive" +version = "0.8.0-beta.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882dc1ea88a82d9fbeeca12d2580094b4919b63b6aa1b102b29db53ffb64f6a3" +dependencies = [ + "ahash", + "bumpalo", + "indexmap", + "slotmap", + "smallvec", +] + +[[package]] +name = "sycamore-web" +version = "0.8.0-beta.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6be07a7ff3eed2e80c25efd24f4bec0a6eeca48b32f128d83ba4221ae3230f0d" +dependencies = [ + "html-escape", + "indexmap", + "js-sys", + "once_cell", + "sycamore-core", + "sycamore-reactive", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "syn" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "once_cell", + "pin-project-lite", + "socket2", + "winapi", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709595b8878a4965ce5e87ebf880a7d39c9afc6837721b21a5a816a8117d921" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "utf8-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +dependencies = [ + "cfg-if 1.0.0", + "serde", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" + +[[package]] +name = "web-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "memory_units", + "winapi", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "yew" +version = "0.19.3" +source = "git+https://github.com/yewstack/yew/#475cf20a86b237694d31fc06a99e9013540bb915" +dependencies = [ + "console_error_panic_hook", + "gloo", + "gloo-utils", + "indexmap", + "js-sys", + "serde", + "slab", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "yew-macro", +] + +[[package]] +name = "yew-macro" +version = "0.19.3" +source = "git+https://github.com/yewstack/yew/#475cf20a86b237694d31fc06a99e9013540bb915" +dependencies = [ + "boolinator", + "lazy_static", + "once_cell", + "prettyplease", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] diff --git a/crates/lgn-editor-gui/Cargo.toml b/crates/lgn-editor-gui/Cargo.toml new file mode 100644 index 0000000000..a24ebef2a9 --- /dev/null +++ b/crates/lgn-editor-gui/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "lgn-editor-gui" +version = "0.1.0" +edition = "2021" + +[dependencies] +async-trait = "0.1.56" +base64 = "0.13.0" +console_log = { version = "0.2.0", features = ["color"] } +getrandom = { version = "0.2.7", features = ["js"] } +gloo-storage = "0.2.1" +log = "0.4.17" +rand = "0.8.5" +reqwest = { version = "0.11.11", features = ["json"] } +serde = { version = "1.0.137", features = ["derive"] } +serde_json = "1.0.81" +sha2 = "0.10.2" +sycamore = { version = "0.8.0-beta.7", features = [ + "suspense", +], optional = true } +thiserror = "1.0.31" +url = "2.2.2" +wasm-bindgen = "0.2.81" +wasm-bindgen-futures = "0.4.31" +web-sys = { version = "0.3.58", features = [ + "Window", + "Document", + "HtmlDocument", +] } +wee_alloc = "0.4.5" +yew = { git = "https://github.com/yewstack/yew/", features = [ + "csr", +], optional = true } + +[profile.release] +panic = 'abort' +codegen-units = 1 +opt-level = 'z' +lto = true + +[features] +default = ["yew"] +# default = ["sycamore"] +yew = ["dep:yew"] +sycamore = ["dep:sycamore"] diff --git a/crates/lgn-editor-gui/index.html b/crates/lgn-editor-gui/index.html new file mode 100644 index 0000000000..b7cecaddea --- /dev/null +++ b/crates/lgn-editor-gui/index.html @@ -0,0 +1,42 @@ + + + + + Editor + + + + + diff --git a/crates/lgn-editor-gui/src/errors.rs b/crates/lgn-editor-gui/src/errors.rs new file mode 100644 index 0000000000..763adca95d --- /dev/null +++ b/crates/lgn-editor-gui/src/errors.rs @@ -0,0 +1,21 @@ +pub trait FromReqwestError { + fn from_reqwest_error(reqwest_error: reqwest::Error) -> Self; +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, thiserror::Error)] +pub enum Error { + #[error("Reqwest error {0}")] + Reqwest(String), + #[error("Dom error {0}")] + Js(String), + #[error("Auth error {0}")] + Auth(String), +} + +impl FromReqwestError for Error { + fn from_reqwest_error(reqwest_error: reqwest::Error) -> Self { + Self::Reqwest(reqwest_error.to_string()) + } +} + +pub type Result = std::result::Result; diff --git a/crates/lgn-editor-gui/src/main.rs b/crates/lgn-editor-gui/src/main.rs new file mode 100644 index 0000000000..00bef4810e --- /dev/null +++ b/crates/lgn-editor-gui/src/main.rs @@ -0,0 +1,82 @@ +use log::{debug, error, Level}; +use wasm_bindgen_futures::spawn_local; + +use crate::utils::auth::get_redirect_uri; +use crate::utils::{ + auth::{get_authorization_url, get_code_in_url, get_token_set}, + dom::{get_cookie, get_current_url, set_cookie, set_window_location}, +}; + +mod errors; +#[cfg(feature = "sycamore")] +mod sycamore; +mod types; +mod utils; +#[cfg(feature = "yew")] +mod yew; + +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + +static COOKIE_NAME: &str = "editor_yew_local"; + +fn main() { + spawn_local(async { + console_log::init_with_level(Level::Trace).unwrap(); + + let current_url = get_current_url().unwrap(); + + match get_code_in_url(¤t_url) { + Some(code) => { + debug!("Code {}", code); + + match get_token_set(&code).await { + Ok(token_set) => { + debug!("Token set {:#?}", token_set); + + set_cookie( + COOKIE_NAME, + token_set.access_token, + Some(token_set.expires_in), + ) + .unwrap(); + + // TODO: Use yew redirections? + set_window_location(&get_redirect_uri().unwrap()).unwrap(); + } + Err(err) => { + error!("Impossible to get token set: {}", err); + } + } + } + None => { + let token = match get_cookie(COOKIE_NAME).unwrap() { + Some(token) => token, + None => { + let authorization_url = get_authorization_url().unwrap(); + + debug!("Authorization url {}", authorization_url); + + set_window_location(&authorization_url).unwrap(); + + return; + } + }; + + #[cfg(feature = "yew")] + ::yew::Renderer::::with_props( + crate::yew::components::app::AppProps::new(token), + ) + .render(); + + #[cfg(feature = "sycamore")] + ::sycamore::render(|cx| { + crate::sycamore::components::app::App( + cx, + crate::sycamore::components::app::AppProps::new(token), + ) + }); + } + } + }); +} diff --git a/crates/lgn-editor-gui/src/sycamore/components/app.rs b/crates/lgn-editor-gui/src/sycamore/components/app.rs new file mode 100644 index 0000000000..b4cca156d2 --- /dev/null +++ b/crates/lgn-editor-gui/src/sycamore/components/app.rs @@ -0,0 +1,70 @@ +use std::rc::Rc; + +use sycamore::prelude::*; + +use crate::{sycamore::hooks::create_async_data, types::TodosRequest}; + +use super::{layout::Topbar, resource_browser::ResourceBrowser}; + +#[derive(Prop)] +pub struct AppProps { + token: Rc, +} + +impl AppProps { + pub fn new(token: String) -> Self { + Self { + token: Rc::new(token), + } + } +} + +#[component] +pub fn App(cx: Scope, props: AppProps) -> View { + let counter = create_signal(cx, 0); + + let todos = create_async_data::(cx, props.token); + + provide_context(cx, todos); + + let inc = { + move |_| { + let value = *counter.get() + 1; + + counter.set(value); + } + }; + + let dec = { + move |_| { + let value = *counter.get() - 1; + + counter.set(value); + } + }; + + view! { cx, + div(class="h-full w-full flex flex-col flex-shrink-0") { + Topbar {} + div(class="flex flex-row flex-grow h-full text-white") { + div(class="w-[300px] border-r border-[#101010] overflow-y-auto p-2") { + ResourceBrowser {} + } + div(class="flex-grow flex flex-col text-white") { + div(class="flex-grow border-b border-[#101010] p-2") { "Editor" } + div(class="h-[200px] p-2") { + div { "Misc" } + div(class="flex flex-row space-x-2") { + button(on:click=dec, type="button") { "-1" } + p { (counter.get()) } + button(on:click=inc, type="button") { "+1" } + } + } + } + div(class="w-[300px] border-l border-[#101010] p-2") { + "Property Grid" + } + } + } + } +} diff --git a/crates/lgn-editor-gui/src/sycamore/components/layout.rs b/crates/lgn-editor-gui/src/sycamore/components/layout.rs new file mode 100644 index 0000000000..49fd569b8f --- /dev/null +++ b/crates/lgn-editor-gui/src/sycamore/components/layout.rs @@ -0,0 +1,12 @@ +use sycamore::prelude::*; + +#[component] +pub fn Topbar(cx: Scope) -> View { + view! { cx, + div(class="h-8 text-white bg-[#222] flex justify-between items-center px-4 flex-shrink-0 border-b border-[#101010]") { + div { "Window" } + div { "Legion Sample project" } + div { "User" } + } + } +} diff --git a/crates/lgn-editor-gui/src/sycamore/components/mod.rs b/crates/lgn-editor-gui/src/sycamore/components/mod.rs new file mode 100644 index 0000000000..4ae007ceaf --- /dev/null +++ b/crates/lgn-editor-gui/src/sycamore/components/mod.rs @@ -0,0 +1,3 @@ +pub mod app; +pub mod layout; +pub mod resource_browser; diff --git a/crates/lgn-editor-gui/src/sycamore/components/resource_browser.rs b/crates/lgn-editor-gui/src/sycamore/components/resource_browser.rs new file mode 100644 index 0000000000..627ec19bda --- /dev/null +++ b/crates/lgn-editor-gui/src/sycamore/components/resource_browser.rs @@ -0,0 +1,35 @@ +use sycamore::prelude::*; + +use crate::{errors::Error, sycamore::hooks::AsyncData, types::Todo}; + +#[component] +pub fn ResourceBrowser(cx: Scope) -> View { + let todos = use_context::, Error>>>(cx); + + let todos_list = create_memo(cx, || { + if let AsyncData::Data(ref todos) = *todos.get() { + todos.clone() + } else { + Vec::new() + } + }); + + view! { cx, + (if let AsyncData::Data(_) = *todos.get() { + view! { cx, + div { + Indexed { + iterable: todos_list, + view: |cx, todo| view! { cx, div { (todo.title) } } + } + } + } + } else if let AsyncData::Init = *todos.get() { + view! { cx, div { "Loading" } } + } else if let AsyncData::Error(_) = *todos.get() { + view! { cx, div { "Error" } } + } else { + view! { cx, div { "?" } } + }) + } +} diff --git a/crates/lgn-editor-gui/src/sycamore/hooks/mod.rs b/crates/lgn-editor-gui/src/sycamore/hooks/mod.rs new file mode 100644 index 0000000000..10488f525d --- /dev/null +++ b/crates/lgn-editor-gui/src/sycamore/hooks/mod.rs @@ -0,0 +1,79 @@ +use serde::Deserialize; +use sycamore::futures::spawn_local_scoped; +use sycamore::prelude::*; + +use crate::{errors::FromReqwestError, types::Request}; + +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum AsyncData { + Init, + Data(T), + Error(E), +} + +impl Default for AsyncData { + fn default() -> Self { + Self::Init + } +} + +pub fn create_async_data<'a, R>( + cx: Scope<'a>, + options: ::Options, +) -> RcSignal::Output, ::Error>> +where + R: Request, + ::Error: 'a + FromReqwestError, + ::Output: 'a + for<'de> Deserialize<'de>, + ::Options: 'a, +{ + let state = create_rc_signal(AsyncData::default()); + + spawn_local_scoped(cx, { + let state = state.clone(); + + async move { + let client = reqwest::Client::new(); + + let req = R::request(options); + + let res = match client.execute(req).await { + Ok(res) => res, + Err(error) => { + state.set(AsyncData::Error( + <::Error>::from_reqwest_error(error), + )); + + return; + } + }; + + let data = match res.json::<::Output>().await { + Ok(data) => data, + Err(error) => { + state.set(AsyncData::Error( + <::Error>::from_reqwest_error(error), + )); + + return; + } + }; + + state.set(AsyncData::Data(data)); + } + }); + + state +} + +#[allow(dead_code)] +pub fn create_async_data_<'a, R>( + cx: Scope<'a>, +) -> RcSignal::Output, ::Error>> +where + R: Request, + ::Error: 'a + FromReqwestError, + ::Output: 'a + for<'de> Deserialize<'de>, +{ + create_async_data::(cx, ()) +} diff --git a/crates/lgn-editor-gui/src/sycamore/mod.rs b/crates/lgn-editor-gui/src/sycamore/mod.rs new file mode 100644 index 0000000000..7bdb0ef14b --- /dev/null +++ b/crates/lgn-editor-gui/src/sycamore/mod.rs @@ -0,0 +1,2 @@ +pub mod components; +pub mod hooks; diff --git a/crates/lgn-editor-gui/src/types.rs b/crates/lgn-editor-gui/src/types.rs new file mode 100644 index 0000000000..3d3dd16366 --- /dev/null +++ b/crates/lgn-editor-gui/src/types.rs @@ -0,0 +1,150 @@ +use std::rc::Rc; + +use log::debug; +use reqwest::{Method, Url}; +use serde::Deserialize; + +use crate::errors::Error; +use crate::utils::tree::{Tree, TreeVisitor}; + +static BASE_URL: &str = "https://jsonplaceholder.typicode.com"; + +pub trait Request { + type Options; + type Output; + type Error; + + fn request(options: Self::Options) -> reqwest::Request; +} + +#[derive(Debug, Clone, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Todo { + pub user_id: u32, + pub id: u32, + pub title: String, + pub completed: bool, +} + +pub struct TodosRequest; + +impl Request for TodosRequest { + type Options = Rc; + type Output = Vec; + type Error = Error; + + fn request(token: Self::Options) -> reqwest::Request { + let base_url: Url = BASE_URL.parse().unwrap(); + + let url = base_url.join("todos").unwrap(); + + let client = reqwest::Client::new(); + + let mut req = client.request(Method::GET, url); + + req = req.bearer_auth(&*token); + + req.build().unwrap() + } +} + +#[derive(Debug, Clone, PartialEq, Deserialize)] +pub struct ResourceDescription { + id: String, + pub path: String, + version: u32, + #[serde(rename = "type")] + type_: String, +} + +struct ExampleResourceEntryTreeVisitor; + +impl TreeVisitor for ExampleResourceEntryTreeVisitor { + fn visit_value(&self, value: &ResourceEntry, _depth: u8) { + let path = match value { + ResourceEntry::Root => "root", + ResourceEntry::Folder { name, .. } => name, + ResourceEntry::Entry { value, .. } => &value.path, + }; + + debug!("{}", path); + } +} + +#[derive(Debug, PartialEq, Deserialize)] +pub struct NextSearchToken { + pub next_search_token: String, + pub total: u64, + pub resource_descriptions: Vec, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum ResourceEntry { + Root, + Folder { + name: String, + }, + Entry { + name: String, + value: ResourceDescription, + }, +} + +impl ResourceEntry { + #[allow(dead_code)] + pub fn name(&self) -> &str { + match self { + Self::Root => "root", + Self::Folder { name, .. } => name, + Self::Entry { name, .. } => name, + } + } +} + +pub type TreeResourceEntry = Tree>; + +impl From> for TreeResourceEntry { + fn from(next_search_token: Rc) -> Self { + let mut tree = Tree::from_value(Rc::new(ResourceEntry::Root)); + + for resource in &next_search_token.resource_descriptions { + let path = resource.path.as_str()[1..].to_string(); + + let keys = path.split('/').map(Into::into).collect::>(); + + let name = keys.last().unwrap().to_string(); + + tree.insert_at_or_else( + keys, + Rc::new(ResourceEntry::Entry { + name, + value: resource.clone(), + }), + |key| Rc::new(ResourceEntry::Folder { name: key.clone() }), + ); + } + + tree + } +} + +pub struct NextSearchTokenRequest; + +impl Request for NextSearchTokenRequest { + type Options = Rc; + type Output = NextSearchToken; + type Error = Error; + + fn request(token: Self::Options) -> reqwest::Request { + let client = reqwest::Client::new(); + + let mut req = client.request( + Method::GET, + "http://[::1]:5051/v1/spaces/0/workspaces/0/resources/search/?token=", + ); + + req = req.bearer_auth(&*token); + + req.build().unwrap() + } +} diff --git a/crates/lgn-editor-gui/src/utils/auth.rs b/crates/lgn-editor-gui/src/utils/auth.rs new file mode 100644 index 0000000000..f8cb27cc31 --- /dev/null +++ b/crates/lgn-editor-gui/src/utils/auth.rs @@ -0,0 +1,185 @@ +use std::{collections::HashMap, str::FromStr}; + +use gloo_storage::{LocalStorage, Storage}; +use log::debug; +use reqwest::Method; +use serde::Deserialize; +use url::Url; + +use crate::errors::{Error, Result}; + +use super::{dom::get_window, pkce}; + +static AUTHORIZE_URL: &str = + "https://legionlabs-playground.auth.ca-central-1.amazoncognito.com/oauth2/authorize"; + +static TOKEN_URL: &str = + "https://legionlabs-playground.auth.ca-central-1.amazoncognito.com/oauth2/token"; + +static REDIRECT_URI: &str = "http://localhost:3000"; + +static AUTHORIZE_VERIFIER_KEY: &str = "authorize-verifier"; + +static TARGET_URL_KEY: &str = "target-url"; + +pub fn get_redirect_uri() -> Result { + REDIRECT_URI + .parse() + .map_err(|_| Error::Js("couldn't parse redirect url".into())) +} + +fn authorize_url( + response_type: &str, + scopes: Vec, + extra_params: Option>, + redirect_uri: Option, + pkce_challenge: Option, +) -> Result { + let mut authorization_url = Url::from_str(AUTHORIZE_URL) + .map_err(|_| Error::Js("couldn't parse authorization url".into()))?; + + { + let mut query = authorization_url.query_pairs_mut(); + + if let Some(pkce_challenge) = pkce_challenge { + query.append_pair("code_challenge_method", "S256"); + query.append_pair("code_challenge", &pkce_challenge); + } + + query.append_pair("client_id", "5m58nrjfv6kr144prif9jk62di"); + query.append_pair("response_type", response_type); + query.append_pair("scope", &scopes.join(" ")); + + if let Some(redirect_uri) = redirect_uri { + query.append_pair("redirect_uri", redirect_uri.as_str()); + } + + if let Some(extra_params) = extra_params { + for (key, value) in extra_params { + query.append_pair(&key, &value); + } + } + } + + Ok(authorization_url) +} + +pub fn get_authorization_url() -> Result { + let window = get_window()?; + + let verifier = pkce::code_verifier(128); + let challenge = pkce::code_challenge(&verifier); + + let scopes = vec![ + "aws.cognito.signin.user.admin".to_string(), + "email".to_string(), + "https://legionlabs.com/editor/allocate".to_string(), + "openid".to_string(), + "profile".to_string(), + ]; + + let extra_params = + HashMap::from_iter(vec![("identity_provider".to_string(), "Azure".to_string())]); + + let redirect_uri = get_redirect_uri()?; + + let redirect_uri_origin = redirect_uri.origin().unicode_serialization(); + + let authorize_url = authorize_url( + "code", + scopes, + Some(extra_params), + Some(redirect_uri), + Some(challenge), + )?; + + LocalStorage::set(AUTHORIZE_VERIFIER_KEY, verifier) + .map_err(|_| Error::Js("couldn't set authorize verifier value in local storage".into()))?; + + let location_origin = window + .location() + .origin() + .map_err(|_| Error::Js("origin not found in location".into()))?; + + if location_origin == redirect_uri_origin { + LocalStorage::set( + TARGET_URL_KEY, + window + .location() + .href() + .map_err(|_| Error::Js("href not found in location".into()))?, + ) + .map_err(|_| Error::Js("couldn't set target-url verifier value in local storage".into()))?; + } + + Ok(authorize_url) +} + +pub fn get_code_in_url(url: &Url) -> Option { + let mut code = None; + + for (key, value) in url.query_pairs() { + if key.as_ref() == "code" { + code = Some(value.into()); + break; + } + } + + code +} + +#[derive(Debug, Deserialize)] +pub struct TokenSet { + // id_token: String, + pub access_token: String, + // refresh_token: String, + pub expires_in: u64, + // token_type: String, +} + +pub async fn get_token_set(code: impl AsRef) -> Result { + let redirect_uri = get_redirect_uri()?; + + let verifier: Vec = match LocalStorage::get(AUTHORIZE_VERIFIER_KEY) { + Ok(verifier) => verifier, + Err(_) => return Err(Error::Auth("authorize verifier not found".into())), + }; + + LocalStorage::delete(AUTHORIZE_VERIFIER_KEY); + + let verifier = + String::from_utf8(verifier).map_err(|_| Error::Js("verifier is not utf-8".into()))?; + + debug!("Verifier {}", verifier); + + let token_url = + Url::from_str(TOKEN_URL).map_err(|_| Error::Js("couldn't parse token url".into()))?; + + let mut body = HashMap::new(); + + body.insert("grant_type", "authorization_code"); + body.insert("client_id", "5m58nrjfv6kr144prif9jk62di"); + body.insert("redirect_uri", redirect_uri.as_str()); + body.insert("code", code.as_ref()); + body.insert("code_verifier", &verifier); + + let client = reqwest::Client::new(); + + let req = client + .request(Method::POST, token_url.as_str()) + .form(&body) + .build() + .map_err(|_| Error::Js("failed to build request".into()))?; + + let res = match client.execute(req).await { + Ok(res) => res, + Err(_) => return Err(Error::Auth("token set request failed".into())), + }; + + let token_set = res + .json() + .await + .map_err(|_| Error::Js("failed to parse token set payload".into()))?; + + Ok(token_set) +} diff --git a/crates/lgn-editor-gui/src/utils/dom.rs b/crates/lgn-editor-gui/src/utils/dom.rs new file mode 100644 index 0000000000..33a0eeb23c --- /dev/null +++ b/crates/lgn-editor-gui/src/utils/dom.rs @@ -0,0 +1,83 @@ +use url::Url; +use wasm_bindgen::JsCast; +use web_sys::{HtmlDocument, Window}; + +use crate::errors::{Error, Result}; + +pub fn get_window() -> Result { + web_sys::window().ok_or_else(|| Error::Js("window object not found".into())) +} + +fn html_document() -> Result { + get_window()? + .document() + .ok_or_else(|| Error::Js("document object not found".into()))? + .dyn_into::() + .map_err(|_| Error::Js("document object couldn't be cast to html document".into())) +} + +pub fn set_cookie( + name: impl AsRef, + value: impl AsRef, + max_age: Option, +) -> Result<()> { + let html_document = html_document()?; + + let location = get_current_url()?; + + let domain = location + .host_str() + .ok_or_else(|| Error::Js("href not found in location".into()))?; + + let mut cookie = format!( + "{name}={value};domain={domain};path=/;samesite=strict;secure;", + name = name.as_ref(), + value = value.as_ref(), + domain = domain, + ); + + if let Some(max_age) = max_age { + cookie.push_str(&format!("max-age={max_age}", max_age = max_age)); + } + + html_document + .set_cookie(&cookie) + .map_err(|_| Error::Js("couldn't set cookie".into())) +} + +pub fn get_cookie(name: impl AsRef) -> Result> { + let cookie = html_document()? + .cookie() + .map_err(|_| Error::Js("couldn't get cookies from document".into()))?; + + for cookie in cookie.split(';') { + let parts = cookie.split('=').collect::>(); + + if parts.len() != 2 || parts.get(0).map(|part| part.trim()) != Some(name.as_ref()) { + continue; + } + + return Ok(parts.get(1).map(|part| part.trim().to_string())); + } + + Ok(None) +} + +pub fn get_current_url() -> Result { + get_window()? + .location() + .href() + .map_err(|_| Error::Js("href not found in location".into()))? + .parse() + .map_err(|_| Error::Js("couldn't parse current url".into())) +} + +pub fn set_window_location(url: &Url) -> Result<()> { + let location = get_window()?.location(); + + location + .set_href(url.as_ref()) + .map_err(|_| Error::Js("couldn't set location url".into()))?; + + Ok(()) +} diff --git a/crates/lgn-editor-gui/src/utils/mod.rs b/crates/lgn-editor-gui/src/utils/mod.rs new file mode 100644 index 0000000000..cd65783524 --- /dev/null +++ b/crates/lgn-editor-gui/src/utils/mod.rs @@ -0,0 +1,4 @@ +pub mod auth; +pub mod dom; +mod pkce; +pub mod tree; diff --git a/crates/lgn-editor-gui/src/utils/pkce.rs b/crates/lgn-editor-gui/src/utils/pkce.rs new file mode 100644 index 0000000000..e60c8259b8 --- /dev/null +++ b/crates/lgn-editor-gui/src/utils/pkce.rs @@ -0,0 +1,44 @@ +// Taken from https://github.com/GabrielRPrada/pkce-rs/blob/master/src/lib.rs +// Works when targetting wasm + +use rand::{thread_rng, Rng}; +use sha2::{Digest, Sha256}; + +const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789-.~_"; + +pub fn code_verifier(length: usize) -> Vec { + assert!( + (43..=128).contains(&length), + "Code verifier length must be between 43 and 128 bytes" + ); + + let mut rng = thread_rng(); + + (0..length) + .map(|_| { + let i = rng.gen_range(0..CHARS.len()); + CHARS[i] + }) + .collect() +} + +fn base64_url_encode(input: &[u8]) -> String { + let b64 = base64::encode(input); + b64.chars() + .filter_map(|c| match c { + '=' => None, + '+' => Some('-'), + '/' => Some('_'), + x => Some(x), + }) + .collect() +} + +pub fn code_challenge(code_verifier: &[u8]) -> String { + let mut sha = Sha256::new(); + sha.update(code_verifier); + let result = sha.finalize(); + base64_url_encode(&result[..]) +} diff --git a/crates/lgn-editor-gui/src/utils/tree.rs b/crates/lgn-editor-gui/src/utils/tree.rs new file mode 100644 index 0000000000..643843e2ba --- /dev/null +++ b/crates/lgn-editor-gui/src/utils/tree.rs @@ -0,0 +1,352 @@ +#![allow(dead_code)] +use std::{borrow::Borrow, collections::BTreeMap, fmt::Debug, hash::Hash}; + +pub trait TreeVisitor { + fn visit_tree(&self, tree: &Tree, depth: u8) { + visit_tree(self, tree, depth); + } + + fn visit_tree_key(&self, key: &K, depth: u8) { + visit_tree_key(self, key, depth); + } + + fn visit_value(&self, value: &T, depth: u8) { + visit_value(self, value, depth); + } +} + +pub fn visit_tree(visitor: &V, tree: &Tree, depth: u8) +where + V: TreeVisitor + ?Sized, +{ + if let Some(ref value) = tree.value { + visitor.visit_value(value, depth); + } + + tree.sub.iter().for_each(|(key, sub_tree)| { + visitor.visit_tree(sub_tree, depth); + visitor.visit_tree_key(key, depth); + }); +} + +pub fn visit_tree_key(_visitor: &V, _key: &K, _depth: u8) +where + V: TreeVisitor + ?Sized, +{ +} + +pub fn visit_value(_visitor: &V, _value: &T, _depth: u8) +where + V: TreeVisitor + ?Sized, +{ +} + +pub trait TreeVisitorMut { + fn visit_tree_mut(&mut self, tree: &Tree, depth: u8) { + visit_tree_mut(self, tree, depth); + } + + fn visit_tree_key_mut(&mut self, key: &K, depth: u8) { + visit_tree_key_mut(self, key, depth); + } + + fn visit_value_mut(&mut self, value: &T, depth: u8) { + visit_value_mut(self, value, depth); + } +} + +pub fn visit_tree_mut(visitor: &mut V, tree: &Tree, depth: u8) +where + V: TreeVisitorMut + ?Sized, +{ + if let Some(ref value) = tree.value { + visitor.visit_value_mut(value, depth); + } + + tree.sub.iter().for_each(|(key, sub_tree)| { + visitor.visit_tree_mut(sub_tree, depth + 1); + visitor.visit_tree_key_mut(key, depth + 1); + }); +} + +pub fn visit_tree_key_mut(_visitor: &mut V, _key: &K, _depth: u8) +where + V: TreeVisitorMut + ?Sized, +{ +} + +pub fn visit_value_mut(_visitor: &mut V, _value: &T, _depth: u8) +where + V: TreeVisitorMut + ?Sized, +{ +} + +#[derive(Debug)] +pub struct Tree { + value: Option, + sub: BTreeMap>, +} + +impl Default for Tree { + fn default() -> Self { + Self { + value: None, + sub: BTreeMap::new(), + } + } +} + +impl Tree +where + K: Eq + Hash, +{ + pub fn new() -> Self { + Self::default() + } + + pub fn from_value(value: T) -> Self { + Self { + value: Some(value), + sub: BTreeMap::new(), + } + } + + pub fn value(&self) -> &Option { + &self.value + } + + pub fn set_value(&mut self, value: T) { + self.value = Some(value); + } + + pub fn clear_value(&mut self) { + self.value = None; + } + + pub fn get(&self, key: &Q) -> Option<&Self> + where + Q: Ord + ?Sized, + K: Borrow + Ord, + { + self.sub.get(key) + } + + pub fn get_mut(&mut self, key: &Q) -> Option<&mut Self> + where + Q: Ord + ?Sized, + K: Borrow + Ord, + { + self.sub.get_mut(key) + } + + pub fn get_or_else(&mut self, key: K, f: F) -> Option<&Self> + where + F: Fn(&K) -> T, + K: Clone + Ord, + { + self.insert_tree_or_else(key.clone(), f); + + self.get(&key) + } + + pub fn get_or_default(&mut self, key: K) -> Option<&Self> + where + K: Clone + Ord, + { + self.insert_tree_or_default(key.clone()); + + self.get(&key) + } + + pub fn get_or_else_mut(&mut self, key: K, f: F) -> Option<&mut Self> + where + F: Fn(&K) -> T, + K: Clone + Ord, + { + self.insert_tree_or_else(key.clone(), f); + + self.get_mut(&key) + } + + pub fn get_or_default_mut(&mut self, key: K) -> Option<&mut Self> + where + K: Clone + Ord, + { + self.insert_tree_or_default(key.clone()); + + self.get_mut(&key) + } + + pub fn get_at(&self, keys: &[&Q]) -> Option<&Self> + where + Q: Ord + ?Sized, + K: Borrow + Ord, + { + let mut tree = self; + + for key in keys.iter() { + if let Some(sub_tree) = tree.get(*key) { + tree = sub_tree; + } else { + return None; + } + } + + Some(tree) + } + + pub fn get_at_or_else(&mut self, keys: Vec, f: F) -> Option<&Self> + where + F: Fn(&K) -> T, + K: Clone + Ord, + { + let mut tree = self; + + for key in keys.into_iter() { + if let Some(sub_tree) = tree.get_or_else_mut(key, &f) { + tree = sub_tree; + } else { + return None; + } + } + + Some(tree) + } + + pub fn get_at_or_default(&mut self, keys: Vec) -> Option<&Self> + where + K: Clone + Ord, + { + let mut tree = self; + + for key in keys.into_iter() { + if let Some(sub_tree) = tree.get_or_default_mut(key) { + tree = sub_tree; + } else { + return None; + } + } + + Some(tree) + } + + pub fn get_at_mut(&mut self, keys: &[&Q]) -> Option<&mut Self> + where + Q: Ord + ?Sized, + K: Borrow + Ord, + { + let mut tree = self; + + for key in keys.iter() { + if let Some(sub_tree) = tree.get_mut(key) { + tree = sub_tree; + } else { + return None; + } + } + + Some(tree) + } + + pub fn get_at_or_else_mut(&mut self, keys: Vec, f: F) -> Option<&mut Self> + where + F: Fn(&K) -> T, + K: Clone + Ord, + { + let mut tree = self; + + for key in keys.into_iter() { + if let Some(sub_tree) = tree.get_or_else_mut(key, &f) { + tree = sub_tree; + } else { + return None; + } + } + + Some(tree) + } + + pub fn get_at_or_default_mut(&mut self, keys: Vec) -> Option<&mut Self> + where + K: Clone + Ord, + { + let mut tree = self; + + for key in keys.into_iter() { + if let Some(sub_tree) = tree.get_or_default_mut(key) { + tree = sub_tree; + } else { + return None; + } + } + + Some(tree) + } + + pub fn insert(&mut self, key: K, value: Option) -> bool + where + K: Ord, + { + let sub_tree = match value { + Some(value) => Self::from_value(value), + None => Self::new(), + }; + + self.insert_tree(key, sub_tree) + } + + fn insert_tree_or_else(&mut self, key: K, f: F) -> bool + where + F: Fn(&K) -> T, + K: Clone + Ord, + { + let value = f(&key); + + self.insert_tree(key, Self::from_value(value)) + } + + fn insert_tree_or_default(&mut self, key: K) -> bool + where + K: Ord, + { + self.insert_tree(key, Self::default()) + } + + fn insert_tree(&mut self, key: K, sub_tree: Tree) -> bool + where + K: Ord, + { + if self.sub.contains_key(&key) { + return false; + } + + self.sub.insert(key, sub_tree).is_none() + } + + pub fn insert_at(&mut self, keys: Vec, value: T) -> bool + where + K: Clone + Ord, + { + if let Some(tree) = self.get_at_or_default_mut(keys) { + tree.set_value(value); + + return true; + } + + false + } + + pub fn insert_at_or_else(&mut self, keys: Vec, value: T, f: F) -> bool + where + F: Fn(&K) -> T, + K: Clone + Ord, + { + if let Some(tree) = self.get_at_or_else_mut(keys, &f) { + tree.set_value(value); + + return true; + } + + false + } +} diff --git a/crates/lgn-editor-gui/src/yew/components/app.rs b/crates/lgn-editor-gui/src/yew/components/app.rs new file mode 100644 index 0000000000..3f0c0c1ebb --- /dev/null +++ b/crates/lgn-editor-gui/src/yew/components/app.rs @@ -0,0 +1,68 @@ +use std::rc::Rc; + +use yew::prelude::*; + +use super::{layout::Topbar, resource_browser::ResourceBrowser}; + +use crate::yew::contexts::{resources::ResourcesProvider, todos::TodosProvider}; + +#[derive(Debug, PartialEq, Properties)] +pub struct AppProps { + token: Rc, +} + +impl AppProps { + pub fn new(token: String) -> Self { + Self { + token: Rc::new(token), + } + } +} + +#[function_component] +pub fn App(props: &AppProps) -> Html { + let counter = use_state(|| 0); + + let inc = { + let counter = counter.clone(); + + move |_| { + let value = *counter + 1; + counter.set(value); + } + }; + + let dec = { + let counter = counter.clone(); + + move |_| { + let value = *counter - 1; + counter.set(value); + } + }; + + html! { + + +
+ +
+
+
+
{"Editor"}
+
+
{"Misc"}
+
+ +

{ *counter }

+ +
+
+
+
{"Property Grid"}
+
+
+
+
+ } +} diff --git a/crates/lgn-editor-gui/src/yew/components/layout.rs b/crates/lgn-editor-gui/src/yew/components/layout.rs new file mode 100644 index 0000000000..ec190e86c5 --- /dev/null +++ b/crates/lgn-editor-gui/src/yew/components/layout.rs @@ -0,0 +1,12 @@ +use yew::prelude::*; + +#[function_component] +pub fn Topbar() -> Html { + html! { +
+
{"Window"}
+
{"Legion Sample project"}
+
{"User"}
+
+ } +} diff --git a/crates/lgn-editor-gui/src/yew/components/mod.rs b/crates/lgn-editor-gui/src/yew/components/mod.rs new file mode 100644 index 0000000000..4ae007ceaf --- /dev/null +++ b/crates/lgn-editor-gui/src/yew/components/mod.rs @@ -0,0 +1,3 @@ +pub mod app; +pub mod layout; +pub mod resource_browser; diff --git a/crates/lgn-editor-gui/src/yew/components/resource_browser.rs b/crates/lgn-editor-gui/src/yew/components/resource_browser.rs new file mode 100644 index 0000000000..04f99ce254 --- /dev/null +++ b/crates/lgn-editor-gui/src/yew/components/resource_browser.rs @@ -0,0 +1,100 @@ +use std::rc::Rc; + +use yew::prelude::*; + +use crate::{ + types::ResourceEntry, + utils::tree::TreeVisitorMut, + yew::{ + contexts::{resources::ResourcesContext, todos::TodosContext}, + hooks::AsyncData, + }, +}; + +struct ExampleResourceEntryTreeVisitor { + html: Vec, +} + +impl TreeVisitorMut> for ExampleResourceEntryTreeVisitor { + fn visit_value_mut(&mut self, entry: &Rc, depth: u8) { + self.html + .push(html! { }); + } +} + +#[derive(Debug, PartialEq, Properties)] +struct ResourceProps { + depth: u8, + entry: Rc, +} + +#[function_component] +fn Resource(props: &ResourceProps) -> Html { + let in_edition = use_state(|| false); + + let onkeyup = { + let in_edition = in_edition.clone(); + + move |event: KeyboardEvent| { + if &event.key() == "F2" { + in_edition.set(true); + } + + if &event.key() == "Escape" { + in_edition.set(false); + } + } + }; + + let entry_html = match &*props.entry { + ResourceEntry::Root => html! {
{"root"}
}, + ResourceEntry::Folder { name, .. } => { + let style = format!("padding-left: {}px", 16 * props.depth); + + html! {
if *in_edition { {"*"} } {name}
} + } + ResourceEntry::Entry { name, value, .. } => { + let style = format!("padding-left: {}px", 16 * props.depth); + let title = value.path.clone(); + + html! {
if *in_edition { {"*"} } {name}
} + } + }; + + html! { +
+ {entry_html} +
+ } +} + +#[function_component] +pub fn ResourceBrowser() -> Html { + let mut visitor = ExampleResourceEntryTreeVisitor { html: Vec::new() }; + + let todos = use_context::().unwrap(); + + let _todos = match *todos { + AsyncData::Data(ref todos) => { + let todos = todos.iter().map(|todo| { + html! { +
{&todo.title}
+ } + }); + + html! {
{ for todos }
} + } + AsyncData::Init => html! {
{"Loading"}
}, + AsyncData::Error(ref error) => html! {
{"Error: "}{error}
}, + }; + + let todos = html! {}; + + let resources = use_context::().unwrap(); + + if let AsyncData::Data(ref resources) = *resources { + visitor.visit_tree_mut(&resources.clone().into(), 0); + }; + + html! {
{visitor.html}
{todos}
} +} diff --git a/crates/lgn-editor-gui/src/yew/contexts/mod.rs b/crates/lgn-editor-gui/src/yew/contexts/mod.rs new file mode 100644 index 0000000000..7783bc5448 --- /dev/null +++ b/crates/lgn-editor-gui/src/yew/contexts/mod.rs @@ -0,0 +1,2 @@ +pub mod resources; +pub mod todos; diff --git a/crates/lgn-editor-gui/src/yew/contexts/resources.rs b/crates/lgn-editor-gui/src/yew/contexts/resources.rs new file mode 100644 index 0000000000..ceedf3a451 --- /dev/null +++ b/crates/lgn-editor-gui/src/yew/contexts/resources.rs @@ -0,0 +1,29 @@ +use std::rc::Rc; + +use yew::prelude::*; + +use crate::{ + errors::Error, + types::{NextSearchToken, NextSearchTokenRequest}, + yew::hooks::{use_async_data, AsyncData}, +}; + +pub type ResourcesContext = UseStateHandle, Error>>; + +#[derive(Properties, Debug, PartialEq)] +pub struct ResourcesProviderProps { + #[prop_or_default] + pub children: Children, + pub token: Rc, +} + +#[function_component] +pub fn ResourcesProvider(props: &ResourcesProviderProps) -> Html { + let resources = use_async_data::(props.token.clone()); + + html! { + context={resources}> + {props.children.clone()} + > + } +} diff --git a/crates/lgn-editor-gui/src/yew/contexts/todos.rs b/crates/lgn-editor-gui/src/yew/contexts/todos.rs new file mode 100644 index 0000000000..f18fe71dc7 --- /dev/null +++ b/crates/lgn-editor-gui/src/yew/contexts/todos.rs @@ -0,0 +1,29 @@ +use std::rc::Rc; + +use yew::prelude::*; + +use crate::{ + errors::Error, + types::{Todo, TodosRequest}, + yew::hooks::{use_async_data, AsyncData}, +}; + +pub type TodosContext = UseStateHandle>, Error>>; + +#[derive(Properties, Debug, PartialEq)] +pub struct TodosProviderProps { + #[prop_or_default] + pub children: Children, + pub token: Rc, +} + +#[function_component] +pub fn TodosProvider(props: &TodosProviderProps) -> Html { + let todos = use_async_data::(props.token.clone()); + + html! { + context={todos}> + {props.children.clone()} + > + } +} diff --git a/crates/lgn-editor-gui/src/yew/hooks/mod.rs b/crates/lgn-editor-gui/src/yew/hooks/mod.rs new file mode 100644 index 0000000000..0d72b12bec --- /dev/null +++ b/crates/lgn-editor-gui/src/yew/hooks/mod.rs @@ -0,0 +1,86 @@ +use std::rc::Rc; + +use serde::Deserialize; +use wasm_bindgen_futures::spawn_local; +use yew::prelude::*; + +use crate::{errors::FromReqwestError, types::Request}; + +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum AsyncData { + Init, + Data(T), + Error(E), +} + +impl Default for AsyncData { + fn default() -> Self { + Self::Init + } +} + +#[hook] +pub fn use_async_data( + options: ::Options, +) -> UseStateHandle::Output>, ::Error>> +where + R: 'static + Request, + ::Error: FromReqwestError, + ::Output: for<'de> Deserialize<'de>, +{ + let state = use_state(AsyncData::default); + + { + let state = state.clone(); + + use_effect_with_deps( + move |_| { + spawn_local(async move { + let client = reqwest::Client::new(); + + let req = R::request(options); + + let res = match client.execute(req).await { + Ok(res) => res, + Err(error) => { + state.set(AsyncData::Error( + <::Error>::from_reqwest_error(error), + )); + + return; + } + }; + + let data = match res.json::<::Output>().await { + Ok(data) => Rc::new(data), + Err(error) => { + state.set(AsyncData::Error( + <::Error>::from_reqwest_error(error), + )); + + return; + } + }; + + state.set(AsyncData::Data(data)); + }); + + move || {} + }, + (), + ); + } + + state +} + +#[hook] +pub fn use_async_data_( +) -> UseStateHandle::Output>, ::Error>> +where + R: 'static + Request, + ::Error: FromReqwestError, + ::Output: for<'de> Deserialize<'de>, +{ + use_async_data::(()) +} diff --git a/crates/lgn-editor-gui/src/yew/mod.rs b/crates/lgn-editor-gui/src/yew/mod.rs new file mode 100644 index 0000000000..2c2233c774 --- /dev/null +++ b/crates/lgn-editor-gui/src/yew/mod.rs @@ -0,0 +1,3 @@ +pub mod components; +pub mod contexts; +pub mod hooks;