From 21efb10ca8612fccc6785aa819bdca6e42427cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20R=C3=A5gstad?= Date: Sun, 25 Oct 2026 13:18:27 +0000 Subject: [PATCH 1/3] feat: add versioned draft project model and web editor shell --- .gitignore | 4 + Cargo.lock | 4294 ++++--------------------------- Cargo.toml | 7 +- README.md | 54 + Trunk.toml | 6 + app/Cargo.toml | 21 +- app/src/browser.rs | 96 + app/src/editor.css | 1 + app/src/editor/mod.rs | 140 + app/src/lib.rs | 63 +- app/src/model.rs | 449 ++++ app/src/ui.rs | 83 + app/tests/project.rs | 138 + docs/core-integration.md | 21 + fixtures/backgrounds/foyer.png | Bin 0 -> 5622 bytes fixtures/backgrounds/garden.png | Bin 0 -> 7266 bytes fixtures/backgrounds/study.png | Bin 0 -> 5759 bytes runtime.lock.json | 9 + rust-toolchain.toml | 5 + web_view/Cargo.toml | 18 +- web_view/index.html | 11 + web_view/src/main.rs | 9 +- 22 files changed, 1547 insertions(+), 3882 deletions(-) create mode 100644 README.md create mode 100644 Trunk.toml create mode 100644 app/src/browser.rs create mode 100644 app/src/editor.css create mode 100644 app/src/editor/mod.rs create mode 100644 app/src/model.rs create mode 100644 app/src/ui.rs create mode 100644 app/tests/project.rs create mode 100644 docs/core-integration.md create mode 100644 fixtures/backgrounds/foyer.png create mode 100644 fixtures/backgrounds/garden.png create mode 100644 fixtures/backgrounds/study.png create mode 100644 runtime.lock.json create mode 100644 rust-toolchain.toml create mode 100644 web_view/index.html diff --git a/.gitignore b/.gitignore index ea8c4bf..fe50fe7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ /target +/dist +/node_modules +/test-results +/playwright-report diff --git a/Cargo.lock b/Cargo.lock index a482430..2b16dc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,21 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +version = 4 [[package]] name = "ahash" @@ -29,42 +14,12 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "allocator-api2" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anymap" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344" - [[package]] name = "anymap2" version = "0.13.0" @@ -75,49 +30,14 @@ checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" name = "app" version = "0.1.0" dependencies = [ - "base_resolver", - "desktop_resolver", + "base64 0.22.1", "dioxus", - "dioxus-logger", - "serde", - "tracing", - "web_resolver", -] - -[[package]] -name = "ashpd" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd884d7c72877a94102c3715f3b1cd09ff4fac28221add3e57cfbe25c236d093" -dependencies = [ - "async-fs", - "async-net", - "enumflags2", - "futures-channel", - "futures-util", - "rand 0.8.5", + "imagesize", + "js-sys", "serde", - "serde_repr", - "url", - "zbus", -] - -[[package]] -name = "askama_escape" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" - -[[package]] -name = "async-broadcast" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" -dependencies = [ - "event-listener", - "event-listener-strategy", - "futures-core", - "pin-project-lite", + "serde_json", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -132,133 +52,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "async-compression" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" -dependencies = [ - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "async-executor" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" -dependencies = [ - "async-lock", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-io" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix", - "slab", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-net" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" -dependencies = [ - "async-io", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-process" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" -dependencies = [ - "async-channel", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "async-signal" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix", - "signal-hook-registry", - "slab", - "windows-sys 0.52.0", -] - [[package]] name = "async-task" version = "4.7.1" @@ -273,30 +66,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", -] - -[[package]] -name = "atk" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4af014b17dd80e8af9fa689b2d4a211ddba6eb583c1622f35d0cb543f6b17e4" -dependencies = [ - "atk-sys", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", + "syn", ] [[package]] @@ -311,93 +81,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" -[[package]] -name = "axum" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" -dependencies = [ - "async-trait", - "axum-core", - "axum-macros", - "base64", - "bytes", - "futures-util", - "http 1.1.0", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "itoa 1.0.11", - "matchit", - "memchr", - "mime", - "multer", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sha1", - "sync_wrapper 1.0.1", - "tokio", - "tokio-tungstenite", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-core" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 1.1.0", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper 0.1.2", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-macros" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "backtrace" -version = "0.3.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - [[package]] name = "base64" version = "0.21.7" @@ -405,12 +88,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] -name = "base_resolver" -version = "0.1.0" -dependencies = [ - "dioxus", - "serde", -] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bincode" @@ -421,12 +102,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.5.0" @@ -436,21 +111,6 @@ dependencies = [ "serde", ] -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - [[package]] name = "blocking" version = "1.6.1" @@ -470,43 +130,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" -[[package]] -name = "cairo-rs" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" -dependencies = [ - "bitflags 2.5.0", - "cairo-sys-rs", - "glib", - "libc", - "once_cell", - "thiserror", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - [[package]] name = "camino" version = "1.1.7" @@ -539,29 +168,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cc" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cfb" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" -dependencies = [ - "byteorder", - "fnv", - "uuid", -] - [[package]] name = "cfg-expr" version = "0.15.8" @@ -569,7 +175,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", - "target-lexicon", ] [[package]] @@ -579,39 +184,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cfg_aliases" -version = "0.1.1" +name = "ciborium" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] [[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets 0.52.5", -] - -[[package]] -name = "ciborium" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.2" +name = "ciborium-io" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" @@ -625,46 +210,6 @@ dependencies = [ "half", ] -[[package]] -name = "cocoa" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" -dependencies = [ - "bitflags 1.3.2", - "block", - "cocoa-foundation", - "core-foundation", - "core-graphics", - "foreign-types", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" -dependencies = [ - "bitflags 1.3.2", - "block", - "core-foundation", - "core-graphics-types", - "libc", - "objc", -] - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - [[package]] name = "concurrent-queue" version = "2.5.0" @@ -710,12 +255,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "convert_case" version = "0.6.0" @@ -725,73 +264,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "core-graphics" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-graphics-types", - "foreign-types", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.20" @@ -804,43 +276,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cssparser" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa 0.4.8", - "matches", - "phf 0.8.0", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.66", -] - [[package]] name = "darling" version = "0.20.9" @@ -861,7 +296,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -872,7 +307,7 @@ checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -882,100 +317,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.5", + "hashbrown", "lock_api", "once_cell", "parking_lot_core", ] -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case 0.4.0", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.66", -] - -[[package]] -name = "desktop_resolver" -version = "0.1.0" -dependencies = [ - "base_resolver", - "dioxus", - "dioxus-logger", - "serde", - "tracing", -] - -[[package]] -name = "desktop_view" -version = "0.1.0" -dependencies = [ - "app", - "dioxus", - "dioxus-logger", - "tracing", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - [[package]] name = "dioxus" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e50735a28b303b0d67e1b5637fb57e4711bf2776266290cbc987c0adfdabb55" +checksum = "b8e7fe217b50d43b27528b0f24c89b411f742a3e7564d1cfbf85253f967954db" dependencies = [ "dioxus-config-macro", "dioxus-core", "dioxus-core-macro", - "dioxus-desktop", "dioxus-fullstack", "dioxus-hooks", - "dioxus-hot-reload", "dioxus-html", - "dioxus-liveview", "dioxus-router", "dioxus-signals", - "dioxus-ssr", "dioxus-web", - "serde", ] [[package]] name = "dioxus-cli-config" -version = "0.5.0" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d4661064bad2f0b12929faf6c9cea4d94e60217ba6b11ff4146b505a57124b" +checksum = "c7dffc452ed91af6ef772b0d9a5899573f6785314e97c533733ec55413c01df3" dependencies = [ "once_cell", "serde", @@ -985,9 +354,9 @@ dependencies = [ [[package]] name = "dioxus-config-macro" -version = "0.5.0" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebe244197b320dec9e9f38742985fe98c058136ada770df73e9429878ed92863" +checksum = "cb1a1aa34cc04c1f7fcbb7a10791ba773cc02d834fe3ec1fe05647699f3b101f" dependencies = [ "proc-macro2", "quote", @@ -995,9 +364,9 @@ dependencies = [ [[package]] name = "dioxus-core" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "088daa3f45aaa729e9eef32dc0a9393dd709ee906b092089e5839cad1cad7c85" +checksum = "3730d2459ab66951cedf10b09eb84141a6eda7f403c28057cbe010495be156b7" dependencies = [ "futures-channel", "futures-util", @@ -1006,23 +375,24 @@ dependencies = [ "rustc-hash", "serde", "slab", + "slotmap", "tracing", "tracing-subscriber", ] [[package]] name = "dioxus-core-macro" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e29a07448245451334eec2883a394e207f28caedf0a57fd1a903e9ccea0b9531" +checksum = "0d9c0dfe0e6a46626fa716c4aa1d2ccb273441337909cfeacad5bb6fcfb947d2" dependencies = [ "constcat", - "convert_case 0.6.0", + "convert_case", "dioxus-rsx", "prettyplease", "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -1031,90 +401,34 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ea539174bb236e0e7dc9c12b19b88eae3cb574dedbd0252a2d43ea7e6de13e2" -[[package]] -name = "dioxus-desktop" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d85f5008be950e1dd255d947d8037e82e424ccc538892cf251b09a22558dc296" -dependencies = [ - "async-trait", - "cocoa", - "core-foundation", - "dioxus-cli-config", - "dioxus-core", - "dioxus-hooks", - "dioxus-hot-reload", - "dioxus-html", - "dioxus-interpreter-js", - "dunce", - "futures-channel", - "futures-util", - "generational-box", - "global-hotkey", - "infer", - "muda", - "objc", - "objc_id", - "rfd", - "rustc-hash", - "serde", - "serde_json", - "signal-hook", - "slab", - "tao", - "thiserror", - "tokio", - "tracing", - "urlencoding", - "webbrowser", - "wry", -] - [[package]] name = "dioxus-fullstack" -version = "0.5.2" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7fb1a22ff7af8756bc9506eebfbecf374b1c8c57f087c85c752ba8bd767fce" +checksum = "b80f0ac18166302341164e681322e0385131c08a11c3cc1c51ee8df799ab0d3d" dependencies = [ - "anymap", - "async-compression", "async-trait", - "axum", - "base64", + "base64 0.21.7", "bytes", "ciborium", - "dioxus-cli-config", - "dioxus-desktop", "dioxus-hot-reload", "dioxus-lib", - "dioxus-ssr", "dioxus-web", "dioxus_server_macro", "futures-util", - "http 1.1.0", - "hyper", "once_cell", - "pin-project", "serde", "serde_json", "server_fn", - "thiserror", - "tokio", - "tokio-stream", - "tokio-util", - "tower", - "tower-http", - "tower-layer", "tracing", - "tracing-futures", "web-sys", ] [[package]] name = "dioxus-hooks" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a8c7019308a6d8381fce84a51006f207407af265aebc5425871399c98d788e4" +checksum = "fa8f9c661eea82295219d25555d5c0b597e74186b029038ceb5e3700ccbd4380" dependencies = [ "dioxus-core", "dioxus-debug-cell", @@ -1129,9 +443,9 @@ dependencies = [ [[package]] name = "dioxus-hot-reload" -version = "0.5.0" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5a28a2af6655473c6521fb5a428538807b985e8e5f1a8c30e2ab71bd54e637" +checksum = "77d01246cb1b93437fb0bbd0dd11cfc66342d86b4311819e76654f2017ce1473" dependencies = [ "dioxus-core", "dioxus-html", @@ -1143,9 +457,9 @@ dependencies = [ [[package]] name = "dioxus-html" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d612d9732f32adc1852e13e1387a9d5baa710b0b004641b5123def53065c8d" +checksum = "f01a0826f179adad6ea8d6586746e8edde0c602cc86f4eb8e5df7a3b204c4018" dependencies = [ "async-trait", "dioxus-core", @@ -1159,7 +473,6 @@ dependencies = [ "serde-value", "serde_json", "serde_repr", - "tokio", "tracing", "wasm-bindgen", "web-sys", @@ -1167,37 +480,36 @@ dependencies = [ [[package]] name = "dioxus-html-internal-macro" -version = "0.5.0" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1799f34affdb158f6ebec23b46b11f9e65de0bbadbbb781dc68c3eddfe6fd32b" +checksum = "0b96f35a608d0ab8f4ca6f66ce1828354e4ebd41580b12454f490221a11da93c" dependencies = [ - "convert_case 0.6.0", + "convert_case", "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] name = "dioxus-interpreter-js" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc68a22e33562317b40ccc7b2d140017e510745c5d7e062e911c6a4f9042e4b1" +checksum = "351fad098c657d14f3ac2900362d2b86e83c22c4c620a404839e1ab628f3395b" dependencies = [ - "dioxus-core", - "dioxus-html", "js-sys", "md5", "sledgehammer_bindgen", "sledgehammer_utils", "wasm-bindgen", + "wasm-bindgen-futures", "web-sys", ] [[package]] name = "dioxus-lib" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af36a9f985ad68783acf62dc276b0a8f0aa928f1c3b42f78e2ae222b19d445c" +checksum = "8bd39b2c41dd1915dcb91d914ea72d8b646f1f8995aaeff82816b862ec586ecd" dependencies = [ "dioxus-core", "dioxus-core-macro", @@ -1207,59 +519,18 @@ dependencies = [ "dioxus-signals", ] -[[package]] -name = "dioxus-liveview" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc132aacc3eb3d11db8f20afa5f3cfc74147374cc41285488083476a0ed1f17" -dependencies = [ - "axum", - "dioxus-cli-config", - "dioxus-core", - "dioxus-hot-reload", - "dioxus-html", - "dioxus-interpreter-js", - "futures-channel", - "futures-util", - "generational-box", - "rustc-hash", - "serde", - "serde_json", - "slab", - "thiserror", - "tokio", - "tokio-stream", - "tokio-util", - "tracing", -] - -[[package]] -name = "dioxus-logger" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe09dc9773dc1f1bb0d38529203d6555d08f67aadca5cf955ac3d1a9e69880" -dependencies = [ - "console_error_panic_hook", - "tracing", - "tracing-subscriber", - "tracing-wasm", -] - [[package]] name = "dioxus-router" -version = "0.5.0" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4cbbc1aff811aa3715c94a7ca0375be0be34356aba7f3897328d844323519b" +checksum = "c235c5dbeb528c0c2b0424763da812e7500df69b82eddac54db6f4975e065c5f" dependencies = [ "dioxus-cli-config", - "dioxus-fullstack", "dioxus-lib", "dioxus-router-macro", - "dioxus-ssr", "gloo", "gloo-utils 0.1.7", "js-sys", - "tokio", "tracing", "url", "urlencoding", @@ -1269,36 +540,36 @@ dependencies = [ [[package]] name = "dioxus-router-macro" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fcb6e4a203dc816bca720c638562d5a782695dc71d6598de088ce50ba2a0f8" +checksum = "2e7cd1c5137ba361f2150cdea6b3bc9ddda7b1af84b22c9ee6b5499bf43e1381" dependencies = [ "proc-macro2", "quote", "slab", - "syn 2.0.66", + "syn", ] [[package]] name = "dioxus-rsx" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa83056104f63fdc6f7f9fc1137208c7b7648bf88d6c86db1e095f15297a0f3" +checksum = "15c400bc8a779107d8f3a67b14375db07dbd2bc31163bf085a8e9097f36f7179" dependencies = [ "dioxus-core", "internment", "krates", "proc-macro2", "quote", - "syn 2.0.66", + "syn", "tracing", ] [[package]] name = "dioxus-signals" -version = "0.5.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fd04e2b3739d5c12255005cbf3185446e750fc2b3eeee9fa4e83c989132415c" +checksum = "7e3e224cd3d3713f159f0199fc088c292a0f4adb94996b48120157f6a8f8342d" dependencies = [ "dioxus-core", "futures-channel", @@ -1310,32 +581,11 @@ dependencies = [ "tracing", ] -[[package]] -name = "dioxus-ssr" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ba8e16b3c7e154a61d814a39505c910403b9df29a113e2920cd23334a4e71c" -dependencies = [ - "askama_escape", - "async-trait", - "chrono", - "dioxus-core", - "dioxus-html", - "generational-box", - "http 1.1.0", - "lru", - "rustc-hash", - "serde_json", - "thiserror", - "tokio", - "tracing", -] - [[package]] name = "dioxus-web" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75cfbe115b193a05c649a80a54a90a6bdd88779694a617daf27d287d6fb944f" +checksum = "e0855ac81fcc9252a0863930a7a7cbb2504fc1b6efe893489c8d0e23aaeb2cb9" dependencies = [ "async-trait", "console_error_panic_hook", @@ -1358,23 +608,17 @@ dependencies = [ [[package]] name = "dioxus_server_macro" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b723da95503f739f9fc5fb23b6ad1e456f1438a496a0427210fa94e4e0d5fe9" +checksum = "b5ef2cad17001c1155f019cb69adbacd620644566d78a77d0778807bb106a337" dependencies = [ - "convert_case 0.6.0", + "convert_case", "proc-macro2", "quote", "server_fn_macro", - "syn 2.0.66", + "syn", ] -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - [[package]] name = "displaydoc" version = "0.2.4" @@ -1383,139 +627,49 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] -name = "dlopen2" -version = "0.7.0" +name = "enumset" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", + "enumset_derive", ] [[package]] -name = "dlopen2_derive" -version = "0.4.0" +name = "enumset_derive" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" dependencies = [ + "darling", "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] -name = "dtoa" -version = "1.0.9" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "dtoa-short" -version = "0.3.5" +name = "euclid" +version = "0.22.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +checksum = "e0f0eb73b934648cd7a4a61f1b15391cd95dab0b4da6e2e66c2a072c144b4a20" dependencies = [ - "dtoa", + "num-traits", + "serde", ] [[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - -[[package]] -name = "encoding_rs" -version = "0.8.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "endi" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" - -[[package]] -name = "enumflags2" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "enumset" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" -dependencies = [ - "enumset_derive", -] - -[[package]] -name = "enumset_derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[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.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "euclid" -version = "0.22.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f0eb73b934648cd7a4a61f1b15391cd95dab0b4da6e2e66c2a072c144b4a20" -dependencies = [ - "num-traits", - "serde", -] - -[[package]] -name = "event-listener" -version = "5.3.1" +name = "event-listener" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ @@ -1540,74 +694,18 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" -[[package]] -name = "fdeflate" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "field-offset" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" -dependencies = [ - "memoffset", - "rustc_version", -] - [[package]] name = "fixedbitset" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" -[[package]] -name = "flate2" -version = "1.0.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[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.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1617,16 +715,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - [[package]] name = "futures" version = "0.3.30" @@ -1681,10 +769,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand", "futures-core", - "futures-io", - "parking", "pin-project-lite", ] @@ -1696,7 +781,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -1729,257 +814,15 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gdk" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ba081bdef3b75ebcdbfc953699ed2d7417d6bd853347a42a37d76406a33646" -dependencies = [ - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" -dependencies = [ - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", - "once_cell", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gdk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkwayland-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90fbf5c033c65d93792192a49a8efb5bb1e640c419682a58bb96f5ae77f3d4a" -dependencies = [ - "gdk-sys", - "glib-sys", - "gobject-sys", - "libc", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkx11" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2ea8a4909d530f79921290389cbd7c34cb9d623bfe970eaae65ca5f9cd9cce" -dependencies = [ - "gdk", - "gdkx11-sys", - "gio", - "glib", - "libc", - "x11", -] - -[[package]] -name = "gdkx11-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee8f00f4ee46cad2939b8990f5c70c94ff882c3028f3cc5abf950fa4ab53043" -dependencies = [ - "gdk-sys", - "glib-sys", - "libc", - "system-deps", - "x11", -] - [[package]] name = "generational-box" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f132919c96b85c02a067ceae965fd50ace57111e2f55c7384b95ac191f4d966b" +checksum = "557cf2cbacd0504c6bf8c29f52f8071e0de1d9783346713dc6121d7fa1e5d0e0" dependencies = [ "parking_lot", ] -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - -[[package]] -name = "gio" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "once_cell", - "pin-project-lite", - "smallvec", - "thiserror", -] - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi", -] - -[[package]] -name = "glib" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" -dependencies = [ - "bitflags 2.5.0", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror", -] - -[[package]] -name = "glib-macros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" -dependencies = [ - "heck 0.4.1", - "proc-macro-crate 2.0.2", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps", -] - -[[package]] -name = "global-hotkey" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89cb13e8c52c87e28a46eae3e5e65b8f0cd465c4c9e67b13d56c70412e792bc3" -dependencies = [ - "bitflags 2.5.0", - "cocoa", - "crossbeam-channel", - "keyboard-types", - "objc", - "once_cell", - "thiserror", - "windows-sys 0.52.0", - "x11-dl", -] - [[package]] name = "gloo" version = "0.8.1" @@ -2181,147 +1024,25 @@ dependencies = [ ] [[package]] -name = "gobject-sys" -version = "0.18.0" +name = "half" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ - "glib-sys", - "libc", - "system-deps", + "cfg-if", + "crunchy", ] [[package]] -name = "gtk" -version = "0.18.1" +name = "hashbrown" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c4f5e0e20b60e10631a5f06da7fe3dda744b05ad0ea71fee2f47adf865890c" -dependencies = [ - "atk", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps", -] - -[[package]] -name = "gtk3-macros" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6063efb63db582968fb7df72e1ae68aa6360dcfb0a75143f34fc7d616bad75e" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "http" version = "0.2.12" @@ -2330,7 +1051,7 @@ checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", - "itoa 1.0.11", + "itoa", ] [[package]] @@ -2341,105 +1062,7 @@ checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", - "itoa 1.0.11", -] - -[[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" -dependencies = [ - "bytes", - "http 1.1.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" -dependencies = [ - "bytes", - "futures-util", - "http 1.1.0", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "http-range-header" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" - -[[package]] -name = "httparse" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http 1.1.0", - "http-body", - "httparse", - "httpdate", - "itoa 1.0.11", - "pin-project-lite", - "smallvec", - "tokio", -] - -[[package]] -name = "hyper-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" -dependencies = [ - "bytes", - "futures-util", - "http 1.1.0", - "http-body", - "hyper", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core 0.52.0", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", + "itoa", ] [[package]] @@ -2557,7 +1180,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -2579,14 +1202,10 @@ dependencies = [ ] [[package]] -name = "indexmap" -version = "1.9.3" +name = "imagesize" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" [[package]] name = "indexmap" @@ -2595,25 +1214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.5", -] - -[[package]] -name = "infer" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6c16b11a665b26aeeb9b1d7f954cdeb034be38dd00adab4f2ae921a8fee804" -dependencies = [ - "cfb", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", + "hashbrown", ] [[package]] @@ -2622,7 +1223,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04e8e537b529b8674e97e9fb82c10ff168a290ac3867a0295f112061ffbca1ef" dependencies = [ - "hashbrown 0.14.5", + "hashbrown", "parking_lot", ] @@ -2652,69 +1253,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9" -[[package]] -name = "inventory" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" -[[package]] -name = "javascriptcore-rs" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" -dependencies = [ - "bitflags 1.3.2", - "glib", - "javascriptcore-rs-sys", -] - -[[package]] -name = "javascriptcore-rs-sys" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - [[package]] name = "js-sys" version = "0.3.69" @@ -2730,7 +1274,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.5.0", + "bitflags", "serde", "unicode-segmentation", ] @@ -2748,19 +1292,6 @@ dependencies = [ "semver", ] -[[package]] -name = "kuchikiki" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" -dependencies = [ - "cssparser", - "html5ever", - "indexmap 1.9.3", - "matches", - "selectors", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -2773,31 +1304,6 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" -[[package]] -name = "libxdo" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00333b8756a3d28e78def82067a377de7fa61b24909000aeaa2b446a948d14db" -dependencies = [ - "libxdo-sys", -] - -[[package]] -name = "libxdo-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db23b9e7e2b7831bbd8aac0bbeeeb7b68cbebc162b227e7052e8e55829a09212" -dependencies = [ - "libc", - "x11", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - [[package]] name = "litemap" version = "0.7.3" @@ -2832,2253 +1338,751 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" dependencies = [ - "hashbrown 0.14.5", + "hashbrown", ] [[package]] -name = "mac" -version = "0.1.1" +name = "md5" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] -name = "malloc_buf" -version = "0.0.6" +name = "memchr" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] -name = "markup5ever" -version = "0.11.0" +name = "nu-ansi-term" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen 0.10.0", - "string_cache", - "string_cache_codegen", - "tendril", + "overload", + "winapi", ] [[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "md5" -version = "0.7.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] [[package]] -name = "memchr" -version = "2.7.4" +name = "once_cell" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "memoffset" -version = "0.9.1" +name = "ordered-float" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" dependencies = [ - "autocfg", + "num-traits", ] [[package]] -name = "mime" -version = "0.3.17" +name = "overload" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] -name = "mime_guess" -version = "2.0.4" +name = "parking" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] -name = "miniz_oxide" -version = "0.7.3" +name = "parking_lot" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ - "adler", - "simd-adler32", + "lock_api", + "parking_lot_core", ] [[package]] -name = "mio" -version = "0.8.11" +name = "parking_lot_core" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ + "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - -[[package]] -name = "muda" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c47e7625990fc1af2226ea4f34fb2412b03c12639fcb91868581eb3a6893453" -dependencies = [ - "cocoa", - "crossbeam-channel", - "gtk", - "keyboard-types", - "libxdo", - "objc", - "once_cell", - "png", - "thiserror", - "windows-sys 0.52.0", + "redox_syscall", + "smallvec", + "windows-targets", ] [[package]] -name = "multer" -version = "3.1.0" +name = "percent-encoding" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http 1.1.0", - "httparse", - "memchr", - "mime", - "spin", - "version_check", -] +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] -name = "ndk" -version = "0.7.0" +name = "petgraph" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ - "bitflags 1.3.2", - "jni-sys", - "ndk-sys", - "num_enum", - "raw-window-handle 0.5.2", - "thiserror", + "fixedbitset", + "indexmap", ] [[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.4.1+23.1.7779620" +name = "pin-project" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ - "jni-sys", + "pin-project-internal", ] [[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nix" -version = "0.27.1" +name = "pin-project-internal" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ - "bitflags 2.5.0", - "cfg-if", - "libc", - "memoffset", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "nodrop" -version = "0.1.14" +name = "pin-project-lite" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] -name = "nu-ansi-term" -version = "0.46.0" +name = "pin-utils" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "num-traits" -version = "0.2.19" +name = "piper" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" dependencies = [ - "autocfg", + "atomic-waker", + "fastrand", + "futures-io", ] [[package]] -name = "num_cpus" -version = "1.16.0" +name = "prettyplease" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ - "hermit-abi 0.3.9", - "libc", + "proc-macro2", + "syn", ] [[package]] -name = "num_enum" -version = "0.5.11" +name = "proc-macro2" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ - "num_enum_derive", + "unicode-ident", ] [[package]] -name = "num_enum_derive" -version = "0.5.11" +name = "quote" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ - "proc-macro-crate 1.3.1", "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", - "objc_exception", ] [[package]] -name = "objc-foundation" -version = "0.1.1" +name = "redox_syscall" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "block", - "objc", - "objc_id", + "bitflags", ] [[package]] -name = "objc_exception" -version = "0.1.2" +name = "rustc-hash" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" -dependencies = [ - "cc", -] +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] -name = "objc_id" -version = "0.1.1" +name = "rustc_version" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "objc", + "semver", ] [[package]] -name = "object" -version = "0.36.0" +name = "ryu" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" -dependencies = [ - "memchr", -] +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] -name = "once_cell" -version = "1.19.0" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "ordered-float" -version = "2.10.1" +name = "semver" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ - "num-traits", + "serde", ] [[package]] -name = "ordered-stream" -version = "0.2.0" +name = "send_wrapper" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" dependencies = [ "futures-core", - "pin-project-lite", ] [[package]] -name = "overload" -version = "0.1.1" +name = "serde" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] [[package]] -name = "pango" -version = "0.18.3" +name = "serde-value" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ - "gio", - "glib", - "libc", - "once_cell", - "pango-sys", + "ordered-float", + "serde", ] [[package]] -name = "pango-sys" -version = "0.18.0" +name = "serde-wasm-bindgen" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", + "js-sys", + "serde", + "wasm-bindgen", ] [[package]] -name = "parking" -version = "2.2.0" +name = "serde_derive" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "parking_lot" -version = "0.12.3" +name = "serde_json" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ - "lock_api", - "parking_lot_core", + "itoa", + "ryu", + "serde", ] [[package]] -name = "parking_lot_core" -version = "0.9.10" +name = "serde_qs" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.5", + "percent-encoding", + "serde", + "thiserror", ] [[package]] -name = "percent-encoding" -version = "2.3.1" +name = "serde_repr" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "petgraph" -version = "0.6.5" +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ - "fixedbitset", - "indexmap 2.2.6", + "form_urlencoded", + "itoa", + "ryu", + "serde", ] [[package]] -name = "phf" -version = "0.8.0" +name = "server_fn" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +checksum = "b06e6e5467a2cd93ce1accfdfd8b859404f0b3b2041131ffd774fabf666b8219" dependencies = [ - "phf_macros", - "phf_shared 0.8.0", - "proc-macro-hack", + "bytes", + "const_format", + "dashmap", + "futures", + "gloo-net 0.5.0", + "http 1.1.0", + "js-sys", + "once_cell", + "send_wrapper", + "serde", + "serde_json", + "serde_qs", + "server_fn_macro_default", + "thiserror", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "xxhash-rust", ] [[package]] -name = "phf" -version = "0.10.1" +name = "server_fn_macro" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +checksum = "09c216bb1c1ac890151397643c663c875a1836adf0b269be4e389cb1b48c173c" dependencies = [ - "phf_shared 0.10.0", + "const_format", + "convert_case", + "proc-macro2", + "quote", + "syn", + "xxhash-rust", ] [[package]] -name = "phf_codegen" -version = "0.8.0" +name = "server_fn_macro_default" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +checksum = "00783df297ec85ea605779f2fef9cbec98981dffe2e01e1a9845c102ee1f1ae6" dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "server_fn_macro", + "syn", ] [[package]] -name = "phf_codegen" -version = "0.10.0" +name = "sharded-slab" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "lazy_static", ] [[package]] -name = "phf_generator" -version = "0.8.0" +name = "slab" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", + "autocfg", ] [[package]] -name = "phf_generator" -version = "0.10.0" +name = "sledgehammer_bindgen" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +checksum = "fcfaf791ff02f48f3518ce825d32cf419c13a43c1d8b1232f74ac89f339c46d2" dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", + "sledgehammer_bindgen_macro", + "wasm-bindgen", ] [[package]] -name = "phf_macros" -version = "0.8.0" +name = "sledgehammer_bindgen_macro" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +checksum = "bdd941cc539bd3dc694edaf9d0c4e1221d02baa67c6b45ec04fad1024d9e8139" dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", - "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] -name = "phf_shared" -version = "0.8.0" +name = "sledgehammer_utils" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +checksum = "f20798defa0e9d4eff9ca451c7f84774c7378a9c3b5a40112cfa2b3eadb97ae2" dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", + "lru", + "once_cell", + "rustc-hash", ] [[package]] -name = "pin-project-internal" -version = "1.1.5" +name = "slotmap" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", + "serde", + "version_check", ] [[package]] -name = "pin-project-lite" -version = "0.2.14" +name = "smallvec" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] -name = "pin-utils" +name = "spinning" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "piper" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "png" -version = "0.17.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "polling" -version = "3.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.4.0", - "pin-project-lite", - "rustix", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "pollster" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "prettyplease" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" -dependencies = [ - "proc-macro2", - "syn 2.0.66", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b" dependencies = [ - "once_cell", - "toml_edit 0.19.15", + "lock_api", ] [[package]] -name = "proc-macro-crate" -version = "2.0.2" +name = "stable_deref_trait" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" -dependencies = [ - "toml_datetime", - "toml_edit 0.20.2", -] +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "syn" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ - "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.109", - "version_check", + "unicode-ident", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "synstructure" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "version_check", + "syn", ] [[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.85" +name = "thiserror" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ - "unicode-ident", + "thiserror-impl", ] [[package]] -name = "quote" -version = "1.0.36" +name = "thiserror-impl" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", + "quote", + "syn", ] [[package]] -name = "rand" -version = "0.7.3" +name = "thread_local" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", + "cfg-if", + "once_cell", ] [[package]] -name = "rand" -version = "0.8.5" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", + "displaydoc", + "zerovec", ] [[package]] -name = "rand_chacha" -version = "0.2.2" +name = "to_method" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] +checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8" [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "tracing" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "pin-project-lite", + "tracing-attributes", + "tracing-core", ] [[package]] -name = "rand_core" -version = "0.5.1" +name = "tracing-attributes" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "getrandom 0.1.16", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "tracing-core" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "getrandom 0.2.15", + "once_cell", + "valuable", ] [[package]] -name = "rand_hc" +name = "tracing-log" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - -[[package]] -name = "raw-window-handle" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" - -[[package]] -name = "redox_syscall" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" -dependencies = [ - "bitflags 2.5.0", -] - -[[package]] -name = "regex" -version = "1.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "rfd" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a73a7337fc24366edfca76ec521f51877b114e42dab584008209cca6719251" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "ashpd", - "block", - "dispatch", - "js-sys", "log", - "objc", - "objc-foundation", - "objc_id", - "pollster", - "raw-window-handle 0.6.2", - "urlencoding", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-sys 0.48.0", + "once_cell", + "tracing-core", ] [[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.4.0" +name = "tracing-subscriber" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ - "semver", + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] -name = "rustix" -version = "0.38.34" +name = "unicode-ident" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.5.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "rustversion" -version = "1.0.17" +name = "unicode-segmentation" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] -name = "ryu" -version = "1.0.18" +name = "unicode-xid" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] -name = "same-file" -version = "1.0.6" +name = "url" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "selectors" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "matches", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", - "thin-slice", -] - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] - -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" -dependencies = [ - "futures-core", -] - -[[package]] -name = "serde" -version = "1.0.203" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float", - "serde", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde_derive" -version = "1.0.203" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "serde_json" -version = "1.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" -dependencies = [ - "itoa 1.0.11", - "ryu", - "serde", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" -dependencies = [ - "itoa 1.0.11", - "serde", -] - -[[package]] -name = "serde_qs" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" -dependencies = [ - "percent-encoding", - "serde", - "thiserror", -] - -[[package]] -name = "serde_repr" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "serde_spanned" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" -dependencies = [ - "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 1.0.11", - "ryu", - "serde", -] - -[[package]] -name = "server_fn" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06e6e5467a2cd93ce1accfdfd8b859404f0b3b2041131ffd774fabf666b8219" -dependencies = [ - "axum", - "bytes", - "const_format", - "dashmap", - "futures", - "gloo-net 0.5.0", - "http 1.1.0", - "http-body-util", - "hyper", - "inventory", - "js-sys", - "once_cell", - "send_wrapper", - "serde", - "serde_json", - "serde_qs", - "server_fn_macro_default", - "thiserror", - "tower", - "tower-layer", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "xxhash-rust", -] - -[[package]] -name = "server_fn_macro" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c216bb1c1ac890151397643c663c875a1836adf0b269be4e389cb1b48c173c" -dependencies = [ - "const_format", - "convert_case 0.6.0", - "proc-macro2", - "quote", - "syn 2.0.66", - "xxhash-rust", -] - -[[package]] -name = "server_fn_macro_default" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00783df297ec85ea605779f2fef9cbec98981dffe2e01e1a9845c102ee1f1ae6" -dependencies = [ - "server_fn_macro", - "syn 2.0.66", -] - -[[package]] -name = "servo_arc" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "sledgehammer_bindgen" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcfaf791ff02f48f3518ce825d32cf419c13a43c1d8b1232f74ac89f339c46d2" -dependencies = [ - "sledgehammer_bindgen_macro", - "wasm-bindgen", -] - -[[package]] -name = "sledgehammer_bindgen_macro" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdd941cc539bd3dc694edaf9d0c4e1221d02baa67c6b45ec04fad1024d9e8139" -dependencies = [ - "quote", - "syn 2.0.66", -] - -[[package]] -name = "sledgehammer_utils" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f20798defa0e9d4eff9ca451c7f84774c7378a9c3b5a40112cfa2b3eadb97ae2" -dependencies = [ - "lru", - "once_cell", - "rustc-hash", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "soup3" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" -dependencies = [ - "futures-channel", - "gio", - "glib", - "libc", - "soup3-sys", -] - -[[package]] -name = "soup3-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spinning" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro2", - "quote", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "sync_wrapper" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck 0.5.0", - "pkg-config", - "toml", - "version-compare", -] - -[[package]] -name = "tao" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ebbccb78deb5a36744c079eea2981b4a48ecbbe6b1b2ffbaa528bea3f5e5db" -dependencies = [ - "bitflags 1.3.2", - "cocoa", - "core-foundation", - "core-graphics", - "crossbeam-channel", - "dispatch", - "dlopen2", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", - "instant", - "jni", - "lazy_static", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc", - "once_cell", - "parking_lot", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.2", - "scopeguard", - "tao-macros", - "unicode-segmentation", - "url", - "windows 0.54.0", - "windows-version", - "x11-dl", -] - -[[package]] -name = "tao-macros" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec114582505d158b669b136e6851f85840c109819d77c42bb7c0709f727d18c2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "target-lexicon" -version = "0.12.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" - -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - -[[package]] -name = "thiserror" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "to_method" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8" - -[[package]] -name = "tokio" -version = "1.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-macros" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "tokio-stream" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite", -] - -[[package]] -name = "tokio-util" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "futures-util", - "hashbrown 0.14.5", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.20.2", -] - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.2.6", - "toml_datetime", - "winnow", -] - -[[package]] -name = "toml_edit" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" -dependencies = [ - "indexmap 2.2.6", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" -dependencies = [ - "bitflags 2.5.0", - "bytes", - "futures-util", - "http 1.1.0", - "http-body", - "http-body-util", - "http-range-header", - "httpdate", - "mime", - "mime_guess", - "percent-encoding", - "pin-project-lite", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[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.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "tracing-wasm" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" -dependencies = [ - "tracing", - "tracing-subscriber", - "wasm-bindgen", -] - -[[package]] -name = "tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.1.0", - "httparse", - "log", - "rand 0.8.5", - "sha1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "uds_windows" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" -dependencies = [ - "memoffset", - "tempfile", - "winapi", -] - -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-segmentation" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "url" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" +checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" dependencies = [ "form_urlencoded", "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "uuid" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version-compare" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[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.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.66", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "wasm-streams" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web_resolver" -version = "0.1.0" -dependencies = [ - "base_resolver", - "dioxus", - "dioxus-logger", - "serde", - "tracing", -] - -[[package]] -name = "web_view" -version = "0.1.0" -dependencies = [ - "app", - "dioxus", - "dioxus-logger", - "serde", - "tracing", -] - -[[package]] -name = "webbrowser" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b" -dependencies = [ - "core-foundation", - "home", - "jni", - "log", - "ndk-context", - "objc", - "raw-window-handle 0.5.2", - "url", - "web-sys", -] - -[[package]] -name = "webkit2gtk" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" -dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "gdk", - "gdk-sys", - "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", - "gtk", - "gtk-sys", - "javascriptcore-rs", - "libc", - "once_cell", - "soup3", - "webkit2gtk-sys", -] - -[[package]] -name = "webkit2gtk-sys" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" -dependencies = [ - "bitflags 1.3.2", - "cairo-sys-rs", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "gtk-sys", - "javascriptcore-rs-sys", - "libc", - "pkg-config", - "soup3-sys", - "system-deps", -] - -[[package]] -name = "webview2-com" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ae9c7e420783826cf769d2c06ac9ba462f450eca5893bb8c6c6529a4e5dd33" -dependencies = [ - "webview2-com-macros", - "webview2-com-sys", - "windows 0.52.0", - "windows-core 0.52.0", - "windows-implement 0.52.0", - "windows-interface 0.52.0", -] - -[[package]] -name = "webview2-com-macros" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "webview2-com-sys" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ad85fceee6c42fa3d61239eba5a11401bf38407a849ed5ea1b407df08cca72" -dependencies = [ - "thiserror", - "windows 0.52.0", - "windows-core 0.52.0", -] - -[[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", + "percent-encoding", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "urlencoding" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] -name = "winapi-util" -version = "0.1.8" +name = "utf16_iter" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" -dependencies = [ - "windows-sys 0.52.0", -] +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] -name = "windows" -version = "0.52.0" +name = "valuable" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core 0.52.0", - "windows-implement 0.52.0", - "windows-interface 0.52.0", - "windows-targets 0.52.5", -] +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] -name = "windows" -version = "0.54.0" +name = "version_check" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" -dependencies = [ - "windows-core 0.54.0", - "windows-implement 0.53.0", - "windows-interface 0.53.0", - "windows-targets 0.52.5", -] +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "windows-core" -version = "0.52.0" +name = "wasm-bindgen" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ - "windows-targets 0.52.5", + "cfg-if", + "wasm-bindgen-macro", ] [[package]] -name = "windows-core" -version = "0.54.0" +name = "wasm-bindgen-backend" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ - "windows-result", - "windows-targets 0.52.5", + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", ] [[package]] -name = "windows-implement" -version = "0.52.0" +name = "wasm-bindgen-futures" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] -name = "windows-implement" -version = "0.53.0" +name = "wasm-bindgen-macro" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942ac266be9249c84ca862f0a164a39533dc2f6f33dc98ec89c8da99b82ea0bd" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ - "proc-macro2", "quote", - "syn 2.0.66", + "wasm-bindgen-macro-support", ] [[package]] -name = "windows-interface" -version = "0.52.0" +name = "wasm-bindgen-macro-support" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] -name = "windows-interface" -version = "0.53.0" +name = "wasm-bindgen-shared" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da33557140a288fae4e1d5f8873aaf9eb6613a9cf82c3e070223ff177f598b60" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] -name = "windows-result" -version = "0.1.2" +name = "wasm-streams" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" dependencies = [ - "windows-targets 0.52.5", + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", ] [[package]] -name = "windows-sys" -version = "0.45.0" +name = "web-sys" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ - "windows-targets 0.42.2", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +name = "web_view" +version = "0.1.0" dependencies = [ - "windows-targets 0.48.5", + "app", + "dioxus", ] [[package]] -name = "windows-sys" -version = "0.52.0" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "windows-targets 0.52.5", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "windows-targets" -version = "0.42.2" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "windows-targets" -version = "0.48.5" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-targets" @@ -5086,73 +2090,28 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", -] - -[[package]] -name = "windows-version" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515" -dependencies = [ - "windows-targets 0.52.5", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.5" @@ -5165,87 +2124,30 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - [[package]] name = "write16" version = "1.0.0" @@ -5258,82 +2160,6 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" -[[package]] -name = "wry" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b717040ba9771fd88eb428c6ea6b555f8e734ff8534f02c13e8f10d97f5935e" -dependencies = [ - "base64", - "block", - "cfg_aliases", - "cocoa", - "core-graphics", - "crossbeam-channel", - "dunce", - "gdkx11", - "gtk", - "html5ever", - "http 0.2.12", - "javascriptcore-rs", - "jni", - "kuchikiki", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc", - "objc_id", - "once_cell", - "percent-encoding", - "raw-window-handle 0.6.2", - "serde", - "serde_json", - "sha2", - "soup3", - "tao-macros", - "thiserror", - "webkit2gtk", - "webkit2gtk-sys", - "webview2-com", - "windows 0.52.0", - "windows-implement 0.52.0", - "windows-version", - "x11-dl", -] - -[[package]] -name = "x11" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "x11-dl" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" -dependencies = [ - "libc", - "once_cell", - "pkg-config", -] - -[[package]] -name = "xdg-home" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "xxhash-rust" version = "0.8.10" @@ -5360,74 +2186,10 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", "synstructure", ] -[[package]] -name = "zbus" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8e3d6ae3342792a6cc2340e4394334c7402f3d793b390d2c5494a4032b3030" -dependencies = [ - "async-broadcast", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-process", - "async-recursion", - "async-task", - "async-trait", - "blocking", - "derivative", - "enumflags2", - "event-listener", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "nix", - "ordered-stream", - "rand 0.8.5", - "serde", - "serde_repr", - "sha1", - "static_assertions", - "tracing", - "uds_windows", - "windows-sys 0.52.0", - "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a3e850ff1e7217a3b7a07eba90d37fe9bb9e89a310f718afcde5885ca9b6d7" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "regex", - "syn 1.0.109", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" -dependencies = [ - "serde", - "static_assertions", - "zvariant", -] - [[package]] name = "zerocopy" version = "0.7.34" @@ -5445,7 +2207,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -5465,7 +2227,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", "synstructure", ] @@ -5488,43 +2250,5 @@ checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", -] - -[[package]] -name = "zvariant" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e09e8be97d44eeab994d752f341e67b3b0d80512a8b315a0671d47232ef1b65" -dependencies = [ - "endi", - "enumflags2", - "serde", - "static_assertions", - "url", - "zvariant_derive", -] - -[[package]] -name = "zvariant_derive" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a5857e2856435331636a9fbb415b09243df4521a267c5bedcd5289b4d5799e" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00bedb16a193cc12451873fee2a1bc6550225acece0e36f333e68326c73c8172" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "syn", ] diff --git a/Cargo.toml b/Cargo.toml index 93484cc..87fe6bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,6 @@ [workspace] - -members = ["app", "base_resolver", "desktop_resolver", "desktop_view", "web_resolver", "web_view"] +resolver = "2" +members = ["app", "web_view"] +# The initial supported platform is browser/WASM. Legacy desktop scaffolding is +# retained outside the workspace until its platform adapter is implemented. +exclude = ["base_resolver", "desktop_resolver", "desktop_view", "web_resolver"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..c2fa040 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# PACE adventure editor + +A Dioxus 0.5.6 editor targeting **web / WebAssembly** first. Rust is pinned to +1.90.0. Desktop and the old resolver crates are retained but excluded from the +supported workspace. + +## Run + +```sh +rustup show # installs rust-toolchain.toml's toolchain and WASM target +cargo install trunk --version 0.21.14 --locked +trunk serve +``` + +Open http://localhost:8080. `trunk build --release` produces a static site in +`dist/`. No server or account is needed for project authoring. + +```sh +cargo test --workspace +cargo check -p web_view --target wasm32-unknown-unknown +cargo fmt --all -- --check +``` + +## Core dependency — blocked + +The inspected `pace_core` commit is +[`6ccfd6ea60534f3c3312882458e1c83308a76b81`](https://github.com/pace-kit/pace_core/tree/6ccfd6ea60534f3c3312882458e1c83308a76b81). +It contains empty build/debug modules and Bevy templates, but no versioned scene +format, loader, executable runtime, or three-room fixture. No other branches or +PRs were available during implementation. `runtime.lock.json` records this +fact; its null runtime revision is **not** a runnable runtime pin. + +Projects currently use **`pace-editor-draft`, version 1**, an explicitly +editor-owned contract, not a claimed implementation of the missing core format. +Core save/import, runtime preview, and game export cannot be completed until +that dependency exists. Draft files are deliberately named `.pace-draft.json`. +No upstream compatibility is implied. + +## Project files + +The JSON envelope includes its format/version, project title, start-room ID, +stable object IDs, embedded PNG/JPEG/WebP backgrounds, normalized hotspot +rectangles, room links, items, dialogue nodes and choices. Embedded images make +files portable without absolute paths or missing asset folders. Limits: 8 MiB +per background, 16,384 pixels per dimension, 64 MiB per project file. + +Unknown fields, unknown versions, duplicate IDs, and malformed files are rejected +before replacing the current project. Broken references remain editable and are +reported against their owning objects. Deleting a referenced object deliberately +leaves those references visible; undo restores it. History retains 50 edits. +Save downloads the full project and attempts an atomic browser recovery copy. +Recovery is origin-specific and limited by browser quota; a warning instructs you +to save a file if it is unavailable. Project files are the portable source of +truth. Keep a downloaded copy before clearing browser data. diff --git a/Trunk.toml b/Trunk.toml new file mode 100644 index 0000000..ed8ada4 --- /dev/null +++ b/Trunk.toml @@ -0,0 +1,6 @@ +[build] +target = "web_view/index.html" +dist = "dist" +[serve] +addresses = ["0.0.0.0"] +port = 8080 diff --git a/app/Cargo.toml b/app/Cargo.toml index a5738ae..1833d4b 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -4,19 +4,16 @@ version = "0.1.0" edition = "2021" [dependencies] +dioxus = { version = "=0.5.6", default-features = false, features = ["macro", "html", "signals", "hooks"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +base64 = "0.22" +imagesize = "0.13" -base_resolver = { path = "../base_resolver" } -web_resolver = { path = "../web_resolver" } -desktop_resolver = { path = "../desktop_resolver" } - -serde = { version = "1.0.197", features = ["derive"] } - -dioxus = { version = "0.5", features = ["router"] } - -# Debug -tracing = "0.1.40" -dioxus-logger = "0.5.0" +[target.'cfg(target_arch = "wasm32")'.dependencies] +wasm-bindgen = "0.2" +web-sys = { version = "0.3", features = ["Window", "Storage", "Document", "Element", "DomRect", "HtmlElement", "HtmlAnchorElement", "Blob", "BlobPropertyBag", "Url"] } +js-sys = "0.3" [features] web = [] -desktop = [] diff --git a/app/src/browser.rs b/app/src/browser.rs new file mode 100644 index 0000000..6fe1e46 --- /dev/null +++ b/app/src/browser.rs @@ -0,0 +1,96 @@ +//! Small browser boundary; the editor model and history are platform independent. +#[cfg(target_arch = "wasm32")] +mod web { + use wasm_bindgen::JsCast; + const RECOVERY_KEY: &str = "pace.editor.draft.v1"; + pub fn load() -> Result, String> { + web_sys::window() + .ok_or("Browser window unavailable")? + .local_storage() + .map_err(|_| "Recovery storage is unavailable")? + .ok_or("Recovery storage is unavailable")? + .get_item(RECOVERY_KEY) + .map_err(|_| "Cannot read browser recovery".into()) + } + pub fn recover(text: &str) -> Result<(), String> { + web_sys::window().ok_or("Browser window unavailable")?.local_storage().map_err(|_| "Recovery storage is unavailable")? + .ok_or("Recovery storage is unavailable")?.set_item(RECOVERY_KEY, text) + .map_err(|_| "Browser recovery is full or unavailable. Save a project file now; your edits remain open.".into()) + } + pub fn confirm(message: &str) -> bool { + web_sys::window() + .and_then(|w| w.confirm_with_message(message).ok()) + .unwrap_or(false) + } + pub fn download(text: &str) -> Result<(), String> { + let doc = web_sys::window() + .and_then(|w| w.document()) + .ok_or("Document unavailable")?; + let chunks = js_sys::Array::new(); + chunks.push(&text.into()); + let mut options = web_sys::BlobPropertyBag::new(); + options.type_("application/json"); + let blob = web_sys::Blob::new_with_str_sequence_and_options(&chunks, &options) + .map_err(|_| "Cannot prepare project file")?; + let url = web_sys::Url::create_object_url_with_blob(&blob) + .map_err(|_| "Cannot prepare download")?; + let anchor: web_sys::HtmlAnchorElement = doc + .create_element("a") + .map_err(|_| "Cannot prepare download")? + .dyn_into() + .map_err(|_| "Cannot create download link")?; + anchor.set_href(&url); + anchor.set_download("adventure.pace-draft.json"); + let body = doc.body().ok_or("Document body unavailable")?; + body.append_child(&anchor) + .map_err(|_| "Cannot attach download")?; + anchor.click(); + anchor.remove(); + // Revoke after the browser has consumed the click, not before navigation. + let callback = wasm_bindgen::closure::Closure::once_into_js(move || { + let _ = web_sys::Url::revoke_object_url(&url); + }); + if let Some(window) = web_sys::window() { + let _ = window.set_timeout_with_callback_and_timeout_and_arguments_0( + callback.unchecked_ref(), + 1000, + ); + } + Ok(()) + } + pub fn stage_point(x: f64, y: f64) -> Option<(f64, f64)> { + let rect = web_sys::window()? + .document()? + .get_element_by_id("room-stage")? + .get_bounding_client_rect(); + if rect.width() <= 0. || rect.height() <= 0. { + return None; + } + Some(( + ((x - rect.x()) / rect.width()).clamp(0., 1.), + ((y - rect.y()) / rect.height()).clamp(0., 1.), + )) + } +} +#[cfg(target_arch = "wasm32")] +pub use web::*; +#[cfg(not(target_arch = "wasm32"))] +pub fn load() -> Result, String> { + Ok(None) +} +#[cfg(not(target_arch = "wasm32"))] +pub fn recover(_: &str) -> Result<(), String> { + Ok(()) +} +#[cfg(not(target_arch = "wasm32"))] +pub fn confirm(_: &str) -> bool { + false +} +#[cfg(not(target_arch = "wasm32"))] +pub fn download(_: &str) -> Result<(), String> { + Err("Downloads require the web platform".into()) +} +#[cfg(not(target_arch = "wasm32"))] +pub fn stage_point(_: f64, _: f64) -> Option<(f64, f64)> { + None +} diff --git a/app/src/editor.css b/app/src/editor.css new file mode 100644 index 0000000..2ccc8dd --- /dev/null +++ b/app/src/editor.css @@ -0,0 +1 @@ +:root{font-family:'DM Sans',system-ui,sans-serif;color:#263d3c;background:#f5f6f3;font-synthesis:none;font-size:14px}*{box-sizing:border-box}body{margin:0}button,input,select,textarea{font:inherit}button,.button{display:inline-flex;align-items:center;justify-content:center;gap:6px;border:1px solid #d9dfda;background:#fff;color:#263d3c;border-radius:7px;padding:9px 13px;cursor:pointer;text-decoration:none;font-weight:600}button:hover,.button:hover{background:#edf2e9;border-color:#9cae9d}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,.stage:focus-visible{outline:3px solid #85b2ea;outline-offset:2px}button:disabled{opacity:.45;cursor:not-allowed}.primary{background:#224c43;color:#fff;border-color:#224c43}.primary:hover{background:#16392f}.button input[type=file]{position:absolute;width:1px;height:1px;opacity:0}.button:focus-within{outline:3px solid #85b2ea}h1,h2,h3,p{margin:0}h1,h2,h3{font-family:Manrope,system-ui,sans-serif}h2{font-size:17px}h3{font-size:12px;letter-spacing:.06em;margin:24px 0 12px}p{line-height:1.65;color:#6d7d76}label{display:flex;flex-direction:column;gap:7px;font-size:12px;font-weight:600;margin:16px 0}input:not([type=file]),select,textarea{width:100%;padding:10px;border:1px solid #d9dfda;border-radius:6px;background:#fff;color:#263d3c}textarea{min-height:90px;resize:vertical}.app{display:flex;flex-direction:column;min-height:100vh}.topbar{height:76px;display:flex;align-items:center;gap:12px;padding:0 24px;background:#fff;border-bottom:1px solid #e1e6e0}.brand{font-family:Manrope,sans-serif;font-weight:800;background:#224c43;color:#d9e8aa;width:38px;height:42px;border-radius:12px 12px 12px 2px;font-size:27px;text-align:center;padding-top:2px}.brand-copy{display:flex;flex-direction:column;gap:2px}.brand-copy strong{font-size:16px;letter-spacing:.13em}.brand-copy span{font-size:10px;color:#78867f}.project-title{margin:auto;font-weight:600}.dependency-banner{font-size:11px;padding:9px 24px;background:#edf0df;color:#69734b;border-bottom:1px solid #dfe3ce}.workspace{display:grid;grid-template-columns:220px minmax(320px,1fr) 290px;flex:1;min-height:calc(100vh - 149px)}.sidebar{background:#f9faf7;border-right:1px solid #e0e5dc;padding:24px 14px;display:flex;flex-direction:column}.section-heading{display:flex;align-items:center;justify-content:space-between;margin:28px 10px 12px}.section-heading h2{font-family:inherit;font-size:10px;letter-spacing:.12em;color:#849087}.section-heading button{padding:0;border:0;background:none;font-size:21px}.project-link{justify-content:flex-start;background:none;border:0;font-size:12px}.tree-row{display:flex;justify-content:flex-start;gap:9px;text-align:left;width:100%;border:0;background:none;margin:3px 0;padding:12px}.tree-row.active{background:#e8eddf;color:#234b40}.sidebar-foot{margin-top:auto;padding:48px 10px 0;font-size:11px;color:#849087;line-height:1.5}.main-panel{padding:20px 28px;min-width:0;background:radial-gradient(#dce3d9 .7px,transparent .7px);background-size:16px 16px}.toolbar{display:flex;align-items:center;gap:8px;margin-bottom:24px}.eyebrow{margin-right:auto;color:#859086;font-size:10px;letter-spacing:.12em;font-weight:700}.toolbar button{font-size:11px;padding:7px 11px}.empty-state{padding:90px 20px;text-align:center;max-width:530px;margin:auto}.empty-state h1{font-size:25px;line-height:1.5;margin:18px 0 12px}.empty-icon{display:inline-flex;align-items:center;justify-content:center;font-size:52px;width:90px;height:90px;border-radius:50%;background:#e5ecdd;color:#506c4a}.inspector{padding:26px 22px;background:#fff;border-left:1px solid #e0e5dc;overflow-wrap:anywhere}.issue{display:flex;flex-direction:column;align-items:flex-start;text-align:left;width:100%;font-size:11px;background:#fff8ef;border-color:#f1dfc5;color:#805d28;margin:8px 0;line-height:1.5}.issue span{font-weight:400}.success{color:#357350;font-size:12px}footer{min-height:36px;background:#fff;border-top:1px solid #e0e5dc;padding:9px 24px;font-size:11px;color:#64756c}.muted{font-size:11px;color:#829087;line-height:1.5}.danger{color:#a4473d;border-color:#e9d2cb;margin-top:18px}.room-heading{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px}.room-heading h1{font-size:25px}.room-heading p{font-size:12px;margin-top:6px}.stage{position:relative;box-shadow:0 12px 40px #263d3c18;background:#e2e8df;border-radius:8px;overflow:hidden;user-select:none;touch-action:none}.stage>img{display:block;width:100%;height:100%;pointer-events:none;object-fit:fill}.hotspot{position:absolute;background:#e5f29530;border:2px solid #e5f295;border-radius:3px;padding:0;color:#fff;text-shadow:0 1px 3px #000;font-size:11px;overflow:hidden;min-width:0}.hotspot:hover,.hotspot.selected{background:#e5f29555;border-color:#fff}.stage.drawing .hotspot{pointer-events:none}.ghost{position:absolute;border:2px dashed #fff;background:#e5f29555;pointer-events:none}.stage-caption{display:flex;justify-content:space-between;font-size:11px;color:#829087;margin-top:14px}.hotspot-list{margin-top:30px}.hotspot-row{display:flex;gap:12px;align-items:center;background:#fff;border:1px solid #e1e6dc;border-radius:7px;margin:7px 0;padding:12px;width:100%;text-align:left;font-size:12px;justify-content:flex-start}.hotspot-row span{margin-left:auto;color:#849087;font-size:10px}.fields-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 12px}.fields-grid label{margin:8px 0}.segmented{display:flex;gap:7px;margin:16px 0}.segmented button{font-size:11px}.card{background:#fff;border:1px solid #e1e6dc;border-radius:10px;padding:24px;margin-bottom:18px}.choice{padding:14px;background:#f6f8f1;border-radius:8px;margin:14px 0}.preview-overlay{position:fixed;inset:0;z-index:20;background:#132624e8;display:flex;align-items:center;justify-content:center;padding:24px}.preview{background:#f8f9f4;border-radius:12px;padding:24px;width:min(960px,95vw);max-height:95vh;overflow:auto}.preview .stage{max-height:56vh}.preview-head{display:flex;align-items:center;gap:12px;margin-bottom:16px}.preview-head h2{margin-right:auto}.inventory{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:16px 0;font-size:12px}.chip{background:#e6eddb;padding:7px 11px;border-radius:20px}.dialogue{padding:18px;background:#fff;border:1px solid #d9dfda;border-radius:8px}.dialogue p{margin:8px 0 14px}.dialogue button{margin-right:8px}.preview-note{font-size:11px;color:#93734e;margin:10px 0}.error{color:#a4473d}.inline-actions{display:flex;gap:8px;flex-wrap:wrap}@media(max-width:1050px){.workspace{grid-template-columns:180px minmax(280px,1fr) 250px}.main-panel{padding:18px}.topbar{gap:8px;padding:0 15px}.project-title{font-size:12px}.brand-copy span{display:none}}@media(max-width:760px){.workspace{grid-template-columns:150px 1fr}.inspector{grid-column:1/-1;border-top:1px solid #e0e5dc}.topbar{height:auto;min-height:76px;flex-wrap:wrap;padding:12px}.project-title{flex:1}.brand-copy{display:none}.topbar button,.topbar .button{font-size:11px}.sidebar{padding:12px 6px}.main-panel{padding:14px}.room-heading{align-items:flex-start;gap:8px}.toolbar{flex-wrap:wrap}.eyebrow{width:100%}.empty-state{padding:40px 10px}} diff --git a/app/src/editor/mod.rs b/app/src/editor/mod.rs new file mode 100644 index 0000000..a691e79 --- /dev/null +++ b/app/src/editor/mod.rs @@ -0,0 +1,140 @@ +use crate::model::Project; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Selection { + Project, + Room(String), + Hotspot(String, String), + Item(String), + Dialogue(String), +} + +#[derive(Clone)] +pub struct Editor { + pub project: Project, + pub selection: Selection, + pub dirty: bool, + undo: Vec, + redo: Vec, +} + +impl Default for Editor { + fn default() -> Self { + Self::new(Project::default()) + } +} + +impl Editor { + pub fn new(project: Project) -> Self { + let selection = project + .rooms + .first() + .map(|r| Selection::Room(r.id.clone())) + .unwrap_or(Selection::Project); + Self { + project, + selection, + dirty: false, + undo: vec![], + redo: vec![], + } + } + pub fn edit(&mut self, change: impl FnOnce(&mut Project)) { + let before = self.project.clone(); + change(&mut self.project); + if before != self.project { + self.undo.push(before); + if self.undo.len() > 50 { + self.undo.remove(0); + } + self.redo.clear(); + self.dirty = true; + } + } + pub fn can_undo(&self) -> bool { + !self.undo.is_empty() + } + pub fn can_redo(&self) -> bool { + !self.redo.is_empty() + } + pub fn undo(&mut self) { + if let Some(previous) = self.undo.pop() { + self.redo + .push(std::mem::replace(&mut self.project, previous)); + self.reconcile_selection(); + self.dirty = true; + } + } + pub fn redo(&mut self) { + if let Some(next) = self.redo.pop() { + self.undo.push(std::mem::replace(&mut self.project, next)); + self.reconcile_selection(); + self.dirty = true; + } + } + pub fn open(&mut self, text: &str) -> Result<(), String> { + let project = Project::from_json(text)?; + *self = Self::new(project); + Ok(()) + } + pub fn selected_room(&self) -> Option<&str> { + match &self.selection { + Selection::Room(id) | Selection::Hotspot(id, _) => Some(id), + _ => None, + } + } + pub fn focus(&mut self, id: Option<&str>) { + self.selection = Selection::Project; + if let Some(id) = id { + for room in &self.project.rooms { + if room.id == id { + self.selection = Selection::Room(id.into()); + return; + } + if room.hotspots.iter().any(|h| h.id == id) { + self.selection = Selection::Hotspot(room.id.clone(), id.into()); + return; + } + } + if self.project.items.iter().any(|i| i.id == id) { + self.selection = Selection::Item(id.into()); + } + if let Some(d) = self + .project + .dialogues + .iter() + .find(|d| d.id == id || d.choices.iter().any(|c| c.id == id)) + { + self.selection = Selection::Dialogue(d.id.clone()); + } + } + } + pub fn delete_selection(&mut self) { + let selection = self.selection.clone(); + self.edit(|p| match &selection { + Selection::Room(id) => p.rooms.retain(|r| &r.id != id), + Selection::Hotspot(room_id, id) => { + if let Some(r) = p.room_mut(room_id) { + r.hotspots.retain(|h| &h.id != id); + } + } + Selection::Item(id) => p.items.retain(|i| &i.id != id), + Selection::Dialogue(id) => p.dialogues.retain(|d| &d.id != id), + Selection::Project => {} + }); + // Keep references to deleted objects so validation exposes each affected + // object instead of silently changing the author's intended story. + self.reconcile_selection(); + } + fn reconcile_selection(&mut self) { + let selection = self.selection.clone(); + let id = match &selection { + Selection::Project => None, + Selection::Room(id) + | Selection::Item(id) + | Selection::Dialogue(id) + | Selection::Hotspot(_, id) => Some(id.as_str()), + }; + self.focus(id); + } +} diff --git a/app/src/lib.rs b/app/src/lib.rs index 847174d..e34be3a 100644 --- a/app/src/lib.rs +++ b/app/src/lib.rs @@ -1,59 +1,6 @@ #![allow(non_snake_case)] -mod no_resolver; - -use base_resolver::PartialsResolver; -use dioxus::prelude::*; - -// If neither feature is enabled, -#[cfg(not(any(feature = "web", feature = "desktop")))] -use no_resolver::Resolver; - -// Base case for when both features are enabled -#[cfg(all(feature = "web", feature = "desktop"))] -use no_resolver::Resolver; - -// If feature "web" is enabled, use web_resolver -#[cfg(all(feature = "web", not(feature = "desktop")))] -use web_resolver::Resolver; - -// If feature "desktop" is enabled, use desktop_resolver -#[cfg(all(feature = "desktop", not(feature = "web")))] -use desktop_resolver::Resolver; - -#[derive(Clone, Routable, Debug, PartialEq)] -enum Route { - #[route("/")] - Home {}, - #[route("/blog/:id")] - Blog { id: i32 }, -} - -#[component] -pub fn App() -> Element { - rsx! { - Router:: {} - } -} - -#[component] -fn Blog(id: i32) -> Element { - rsx! { - Link { to: Route::Home {}, "Go to counter" } - "Blog post {id}" - } -} - -#[component] -fn Home() -> Element { - let mut count = use_signal(|| 0); - - rsx! { - Link { to: Route::Blog { id: count() }, "Go to blog" } - div { - h1 { "High-Five counter: {count}" } - button { onclick: move |_| count += 1, "Up high!" } - button { onclick: move |_| count -= 1, "Down low!" } - {Resolver::HomeSub()} - } - } -} +mod browser; +pub mod editor; +pub mod model; +mod ui; +pub use ui::App; diff --git a/app/src/model.rs b/app/src/model.rs new file mode 100644 index 0000000..1101d36 --- /dev/null +++ b/app/src/model.rs @@ -0,0 +1,449 @@ +//! Editor-owned draft contract. This is deliberately NOT named the PACE core +//! format: the inspected upstream revision has no serializable model or runtime. +use base64::{engine::general_purpose::STANDARD, Engine}; +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; + +pub const FORMAT: &str = "pace-editor-draft"; +pub const VERSION: u32 = 1; +pub const MAX_IMAGE_BYTES: usize = 8 * 1024 * 1024; +pub const MAX_PROJECT_BYTES: usize = 64 * 1024 * 1024; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Project { + pub format: String, + pub version: u32, + pub title: String, + pub start_room: Option, + pub rooms: Vec, + pub items: Vec, + pub dialogues: Vec, + next_id: u64, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Room { + pub id: String, + pub name: String, + pub background: Option, + pub hotspots: Vec, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Background { + pub name: String, + pub data_url: String, + pub width: u32, + pub height: u32, +} + +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Rect { + pub x: f64, + pub y: f64, + pub width: f64, + pub height: f64, +} + +impl Rect { + /// Coordinates are normalized to the original image, independent of zoom. + pub fn from_drag(start: (f64, f64), end: (f64, f64)) -> Option { + let (ax, ay) = (start.0.clamp(0., 1.), start.1.clamp(0., 1.)); + let (bx, by) = (end.0.clamp(0., 1.), end.1.clamp(0., 1.)); + let rect = Self { + x: ax.min(bx), + y: ay.min(by), + width: (ax - bx).abs(), + height: (ay - by).abs(), + }; + (rect.valid() && rect.width >= 0.005 && rect.height >= 0.005).then_some(rect) + } + + pub fn valid(&self) -> bool { + [self.x, self.y, self.width, self.height] + .iter() + .all(|n| n.is_finite()) + && self.x >= 0. + && self.y >= 0. + && self.width > 0. + && self.height > 0. + && self.x + self.width <= 1.000001 + && self.y + self.height <= 1.000001 + } + + pub fn translated(self, dx: f64, dy: f64) -> Self { + Self { + x: (self.x + dx).clamp(0., (1. - self.width).max(0.)), + y: (self.y + dy).clamp(0., (1. - self.height).max(0.)), + ..self + } + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Hotspot { + pub id: String, + pub name: String, + pub rect: Rect, + pub action: Action, + pub requires_item: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)] +pub enum Action { + Look { text: String }, + GoTo { room_id: String }, + Take { item_id: String }, + Talk { dialogue_id: String }, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Item { + pub id: String, + pub name: String, + pub description: String, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Dialogue { + pub id: String, + pub name: String, + pub speaker: String, + pub text: String, + pub choices: Vec, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Choice { + pub id: String, + pub text: String, + pub next: Option, + pub give_item: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Issue { + pub object_id: Option, + pub field: String, + pub message: String, +} + +impl Default for Project { + fn default() -> Self { + Self { + format: FORMAT.into(), + version: VERSION, + title: "Untitled adventure".into(), + start_room: None, + rooms: vec![], + items: vec![], + dialogues: vec![], + next_id: 1, + } + } +} + +impl Project { + pub fn to_json(&self) -> Result { + let text = serde_json::to_string_pretty(self).map_err(|e| e.to_string())?; + if text.len() > MAX_PROJECT_BYTES { + return Err("Project exceeds the 64 MiB file limit. Reduce background sizes.".into()); + } + Ok(text) + } + + pub fn from_json(text: &str) -> Result { + if text.len() > MAX_PROJECT_BYTES { + return Err("Project exceeds the 64 MiB file limit.".into()); + } + let value: serde_json::Value = + serde_json::from_str(text).map_err(|e| format!("Invalid project JSON: {e}"))?; + if value.get("format").and_then(|v| v.as_str()) != Some(FORMAT) { + return Err( + "This is not a PACE editor draft. Core-format import awaits the upstream contract." + .into(), + ); + } + if value.get("version").and_then(|v| v.as_u64()) != Some(VERSION as u64) { + return Err("Unsupported draft version. Open it with the editor that created it; no data was replaced.".into()); + } + // Strict decoding prevents silent loss of fields from a newer writer. + let project: Self = serde_json::from_str(text) + .map_err(|e| format!("Unsupported or malformed project: {e}"))?; + // Invalid references are editable, but ambiguous IDs cannot safely be edited. + let mut ids = HashSet::new(); + for id in project.ids() { + if id.trim().is_empty() || !ids.insert(id) { + return Err(format!( + "Empty or duplicate object ID: {id:?}. No data was replaced." + )); + } + } + Ok(project) + } + + fn ids(&self) -> Vec<&str> { + self.rooms + .iter() + .flat_map(|r| { + std::iter::once(r.id.as_str()).chain(r.hotspots.iter().map(|h| h.id.as_str())) + }) + .chain(self.items.iter().map(|i| i.id.as_str())) + .chain(self.dialogues.iter().flat_map(|d| { + std::iter::once(d.id.as_str()).chain(d.choices.iter().map(|c| c.id.as_str())) + })) + .collect() + } + + pub fn allocate_id(&mut self, kind: &str) -> String { + loop { + let id = format!("{kind}-{}", self.next_id); + self.next_id = self.next_id.wrapping_add(1); + if !self.ids().contains(&id.as_str()) { + return id; + } + } + } + + pub fn add_room(&mut self) -> String { + let id = self.allocate_id("room"); + self.rooms.push(Room { + id: id.clone(), + name: format!("Room {}", self.rooms.len() + 1), + background: None, + hotspots: vec![], + }); + if self.start_room.is_none() { + self.start_room = Some(id.clone()); + } + id + } + + pub fn room(&self, id: &str) -> Option<&Room> { + self.rooms.iter().find(|r| r.id == id) + } + pub fn room_mut(&mut self, id: &str) -> Option<&mut Room> { + self.rooms.iter_mut().find(|r| r.id == id) + } + + pub fn add_hotspot(&mut self, room_id: &str, rect: Rect) -> Option { + if !rect.valid() || self.room(room_id)?.background.is_none() { + return None; + } + let id = self.allocate_id("hotspot"); + let room = self.room_mut(room_id)?; + room.hotspots.push(Hotspot { + id: id.clone(), + name: format!("Hotspot {}", room.hotspots.len() + 1), + rect, + action: Action::Look { + text: "Something catches your eye.".into(), + }, + requires_item: None, + }); + Some(id) + } + + pub fn add_item(&mut self) -> String { + let id = self.allocate_id("item"); + self.items.push(Item { + id: id.clone(), + name: "New item".into(), + description: String::new(), + }); + id + } + + pub fn add_dialogue(&mut self) -> String { + let id = self.allocate_id("dialogue"); + self.dialogues.push(Dialogue { + id: id.clone(), + name: "New dialogue".into(), + speaker: "Narrator".into(), + text: "Hello, traveler.".into(), + choices: vec![], + }); + id + } + + pub fn validate(&self) -> Vec { + let mut issues = vec![]; + let mut push = |id: Option<&str>, field: &str, message: String| { + issues.push(Issue { + object_id: id.map(str::to_owned), + field: field.into(), + message, + }) + }; + if self.title.trim().is_empty() { + push(None, "title", "Give the project a title.".into()); + } + if !self + .start_room + .as_deref() + .is_some_and(|id| self.room(id).is_some()) + { + push( + None, + "start_room", + "Choose an existing starting room.".into(), + ); + } + let has_item = |id: &str| self.items.iter().any(|i| i.id == id); + let has_dialogue = |id: &str| self.dialogues.iter().any(|d| d.id == id); + for r in &self.rooms { + if r.name.trim().is_empty() { + push(Some(&r.id), "name", "Room name is empty.".into()); + } + match &r.background { + None => push( + Some(&r.id), + "background", + "Import a background for this room.".into(), + ), + Some(b) => { + if let Err(e) = b.validate() { + push(Some(&r.id), "background", e); + } + } + } + for h in &r.hotspots { + if h.name.trim().is_empty() { + push(Some(&h.id), "name", "Hotspot name is empty.".into()); + } + if !h.rect.valid() { + push( + Some(&h.id), + "rect", + "Hotspot must have a positive size and fit inside the background.".into(), + ); + } + if let Some(id) = &h.requires_item { + if !has_item(id) { + push( + Some(&h.id), + "requires_item", + format!("Required item {id:?} does not exist."), + ); + } + } + match &h.action { + Action::GoTo { room_id } if self.room(room_id).is_none() => push( + Some(&h.id), + "action.room_id", + format!("Linked room {room_id:?} does not exist."), + ), + Action::Take { item_id } if !has_item(item_id) => push( + Some(&h.id), + "action.item_id", + format!("Item {item_id:?} does not exist."), + ), + Action::Talk { dialogue_id } if !has_dialogue(dialogue_id) => push( + Some(&h.id), + "action.dialogue_id", + format!("Dialogue {dialogue_id:?} does not exist."), + ), + Action::Look { text } if text.trim().is_empty() => { + push(Some(&h.id), "action.text", "Enter inspection text.".into()) + } + _ => {} + } + } + } + for item in &self.items { + if item.name.trim().is_empty() { + push(Some(&item.id), "name", "Item name is empty.".into()); + } + } + for d in &self.dialogues { + if d.name.trim().is_empty() { + push(Some(&d.id), "name", "Dialogue name is empty.".into()); + } + if d.text.trim().is_empty() { + push(Some(&d.id), "text", "Enter dialogue text.".into()); + } + for c in &d.choices { + if c.text.trim().is_empty() { + push(Some(&c.id), "text", "Enter choice text.".into()); + } + if let Some(id) = &c.next { + if !has_dialogue(id) { + push( + Some(&c.id), + "next", + format!("Next dialogue {id:?} does not exist."), + ); + } + } + if let Some(id) = &c.give_item { + if !has_item(id) { + push( + Some(&c.id), + "give_item", + format!("Reward item {id:?} does not exist."), + ); + } + } + } + } + issues + } +} + +impl Background { + pub fn import(name: String, bytes: &[u8]) -> Result { + if bytes.len() > MAX_IMAGE_BYTES { + return Err("Background exceeds 8 MiB. Resize it before importing.".into()); + } + let mime = if bytes.starts_with(b"\x89PNG\r\n\x1a\n") { + "image/png" + } else if bytes.starts_with(&[0xff, 0xd8, 0xff]) { + "image/jpeg" + } else if bytes.starts_with(b"RIFF") && bytes.get(8..12) == Some(b"WEBP") { + "image/webp" + } else { + return Err("Use a PNG, JPEG, or WebP image.".into()); + }; + let size = imagesize::blob_size(bytes) + .map_err(|_| "Cannot read this image. It may be corrupt.".to_string())?; + if size.width == 0 || size.height == 0 || size.width > 16384 || size.height > 16384 { + return Err("Image dimensions must be between 1 and 16384 pixels.".into()); + } + Ok(Self { + name, + data_url: format!("data:{mime};base64,{}", STANDARD.encode(bytes)), + width: size.width as u32, + height: size.height as u32, + }) + } + + fn validate(&self) -> Result<(), String> { + let (header, data) = self + .data_url + .split_once(',') + .ok_or("Invalid embedded background.")?; + if data.len() > MAX_IMAGE_BYTES * 4 / 3 + 4 { + return Err("Embedded background exceeds 8 MiB.".into()); + } + let bytes = STANDARD + .decode(data) + .map_err(|_| "Invalid background encoding.")?; + let parsed = Self::import(self.name.clone(), &bytes)?; + if parsed.data_url.split_once(',').map(|p| p.0) != Some(header) + || parsed.width != self.width + || parsed.height != self.height + { + return Err("Background type or dimensions do not match its image data.".into()); + } + Ok(()) + } +} diff --git a/app/src/ui.rs b/app/src/ui.rs new file mode 100644 index 0000000..47b6ced --- /dev/null +++ b/app/src/ui.rs @@ -0,0 +1,83 @@ +use crate::{ + browser, + editor::{Editor, Selection}, +}; +use dioxus::prelude::*; + +#[component] +pub fn App() -> Element { + let mut notice = use_signal(String::new); + let mut editor = use_signal(|| { + let mut editor = Editor::default(); + match browser::load() { + Ok(Some(text)) => match editor.open(&text) { + Ok(()) => notice.set("Recovered your last browser draft.".into()), + Err(e) => notice.set(format!("Recovery was not opened: {e}")), + }, + Err(e) => notice.set(e), + _ => {} + } + editor + }); + let issues = editor.read().project.validate(); + rsx! { + style { {include_str!("editor.css")} } + div { class: "app", + header { class: "topbar", + div { class: "brand", "P" } + div { class: "brand-copy", strong { "PACE" } span { "Adventure editor" } } + div { class: "project-title", "{editor.read().project.title}" } + button { onclick: move |_| { if !editor.read().dirty || browser::confirm("Discard changes that have not been saved to a project file?") { editor.set(Editor::default()); } }, "New project" } + label { class: "button", "Open project" + input { r#type: "file", accept: ".json", "aria-label": "Open project", onchange: move |event: Event| async move { + if editor.read().dirty && !browser::confirm("Replace this project? Save a file first to keep your changes.") { return; } + if let Some(files) = event.files() { + if let Some(name) = files.files().first() { + match files.read_file_to_string(name).await { + Some(text) => match editor.write().open(&text) { Ok(()) => notice.set("Project opened.".into()), Err(e) => notice.set(e) }, + None => notice.set("Could not read project file.".into()), + } + } + } + } } + } + button { class: "primary", onclick: move |_| { + let result = editor.read().project.to_json().and_then(|text| { browser::download(&text)?; Ok(text) }); + match result { Ok(text) => { editor.write().dirty = false; notice.set(match browser::recover(&text) { Ok(()) => "Project file downloaded and browser recovery saved.".into(), Err(e) => format!("Project file downloaded. {e}") }); }, Err(e) => notice.set(e) } + }, "Save project" } + } + div { class: "dependency-banner", "Draft format v1 · PACE core integration pending. Your project files include all imported images." } + div { class: "workspace", + aside { class: "sidebar", + button { class: "project-link", onclick: move |_| editor.write().selection = Selection::Project, "Project settings" } + div { class: "section-heading", h2 { "ROOMS" } button { "aria-label": "Add room", onclick: move |_| { + let mut id = String::new(); editor.write().edit(|p| id = p.add_room()); editor.write().selection = Selection::Room(id); + }, "+" } } + for room in editor.read().project.rooms.clone() { + button { class: if editor.read().selected_room() == Some(room.id.as_str()) { "tree-row active" } else { "tree-row" }, onclick: move |_| editor.write().selection = Selection::Room(room.id.clone()), "{room.name}" } + } + div { class: "sidebar-foot", "Build a world, one room at a time." } + } + main { class: "main-panel", + div { class: "toolbar", + span { class: "eyebrow", "YOUR ADVENTURE" } + button { disabled: !editor.read().can_undo(), onclick: move |_| editor.write().undo(), "Undo" } + button { disabled: !editor.read().can_redo(), onclick: move |_| editor.write().redo(), "Redo" } + } + div { class: "empty-state", span { class: "empty-icon", "◇" } h1 { "Every adventure starts somewhere." } p { "Add a room, import its background, and bring your world to life." } } + } + aside { class: "inspector", + h2 { "Project" } + label { "Project title" input { value: "{editor.read().project.title}", oninput: move |e| editor.write().edit(|p| p.title = e.value()) } } + label { "Starting room" select { value: editor.read().project.start_room.clone().unwrap_or_default(), onchange: move |e| editor.write().edit(|p| p.start_room = if e.value().is_empty() { None } else { Some(e.value()) }), option { value: "", "Choose a room" } for room in editor.read().project.rooms.clone() { option { value: "{room.id}", "{room.name}" } } } } + h3 { "Validation · {issues.len()}" } + if issues.is_empty() { p { class: "success", "Ready for draft authoring." } } + for issue in issues { + button { class: "issue", onclick: move |_| editor.write().focus(issue.object_id.as_deref()), strong { "{issue.field}" } span { "{issue.message}" } } + } + } + } + footer { role: "status", "{notice}" } + } + } +} diff --git a/app/tests/project.rs b/app/tests/project.rs new file mode 100644 index 0000000..d9bed90 --- /dev/null +++ b/app/tests/project.rs @@ -0,0 +1,138 @@ +use app::{ + editor::{Editor, Selection}, + model::*, +}; +fn background() -> Background { + Background::import( + "foyer.png".into(), + include_bytes!("../../fixtures/backgrounds/foyer.png"), + ) + .unwrap() +} +fn project() -> Project { + let mut p = Project::default(); + let room = p.add_room(); + p.room_mut(&room).unwrap().background = Some(background()); + let item = p.add_item(); + let dialogue = p.add_dialogue(); + let choice = p.allocate_id("choice"); + p.dialogues[0].choices.push(Choice { + id: choice, + text: "Thanks!".into(), + next: Some(dialogue.clone()), + give_item: Some(item.clone()), + }); + for action in [ + Action::Look { + text: "A quiet room 🗝".into(), + }, + Action::GoTo { + room_id: room.clone(), + }, + Action::Take { + item_id: item.clone(), + }, + Action::Talk { + dialogue_id: dialogue, + }, + ] { + let id = p + .add_hotspot( + &room, + Rect { + x: 0.1, + y: 0.2, + width: 0.25, + height: 0.3, + }, + ) + .unwrap(); + let h = p.rooms[0].hotspots.iter_mut().find(|h| h.id == id).unwrap(); + h.action = action; + h.requires_item = Some(item.clone()); + } + p +} +#[test] +fn portable_roundtrip_preserves_every_field_and_asset() { + let p = project(); + assert!(p.validate().is_empty()); + let text = p.to_json().unwrap(); + let loaded = Project::from_json(&text).unwrap(); + assert_eq!(loaded, p); + assert_eq!(loaded.to_json().unwrap(), text); +} +#[test] +fn rejects_future_versions_and_unknown_fields_without_replacing_open_project() { + let p = project(); + let mut editor = Editor::new(p.clone()); + for text in [ + p.to_json() + .unwrap() + .replace("\"version\": 1", "\"version\": 2"), + p.to_json() + .unwrap() + .replace("\"title\":", "\"future_field\": true, \"title\":"), + "not json".into(), + ] { + assert!(editor.open(&text).is_err()); + assert_eq!(editor.project, p); + } + let text = p + .to_json() + .unwrap() + .replace("\"speaker\":", "\"future_nested\": 42, \"speaker\":"); + assert!(Project::from_json(&text).is_err()); +} +#[test] +fn duplicate_ids_are_rejected_and_allocated_ids_never_collide_after_reopen() { + let mut p = project(); + p.items[0].id = p.rooms[0].id.clone(); + assert!(Project::from_json(&p.to_json().unwrap()).is_err()); + let mut p = Project::from_json(&project().to_json().unwrap()).unwrap(); + let old = p.rooms[0].id.clone(); + assert_ne!(p.add_room(), old); +} +#[test] +fn missing_references_are_preserved_and_point_to_affected_objects() { + let mut p = project(); + let removed = p.items.remove(0); + let loaded = Project::from_json(&p.to_json().unwrap()).unwrap(); + let issues = loaded.validate(); + assert!(issues.iter().any(|i| i.object_id.as_deref() + == Some(p.rooms[0].hotspots[2].id.as_str()) + && i.field == "action.item_id")); + assert!(issues.iter().any(|i| i.object_id.as_deref() + == Some(p.dialogues[0].choices[0].id.as_str()) + && i.field == "give_item")); + assert_eq!( + loaded.rooms[0].hotspots[0].requires_item.as_deref(), + Some(removed.id.as_str()) + ); +} +#[test] +fn edits_delete_undo_redo_and_failed_open_are_transactional() { + let mut e = Editor::new(project()); + let initial = e.project.clone(); + e.selection = Selection::Room(e.project.rooms[0].id.clone()); + e.delete_selection(); + assert!(e.project.rooms.is_empty()); + assert!(e.project.validate().iter().any(|i| i.field == "start_room")); + e.undo(); + assert_eq!(e.project, initial); + e.redo(); + assert!(e.project.rooms.is_empty()); + e.undo(); + e.edit(|p| p.title = "A new story".into()); + assert!(!e.can_redo()); + assert!(e.dirty); +} +#[test] +fn import_rejects_unsupported_corrupt_or_oversize_images() { + assert!(Background::import("a.svg".into(), b"").is_err()); + assert!(Background::import("bad.png".into(), b"\x89PNG\r\n\x1a\n").is_err()); + assert!(Background::import("huge.png".into(), &vec![0; MAX_IMAGE_BYTES + 1]).is_err()); + let mut p = project(); + p.rooms[0].background.as_mut().unwrap().width += 1; + assert!(p.validate().iter().any(|i| i.field == "background")); +} diff --git a/docs/core-integration.md b/docs/core-integration.md new file mode 100644 index 0000000..457ce45 --- /dev/null +++ b/docs/core-integration.md @@ -0,0 +1,21 @@ +# Core integration boundary + +Do not reinterpret the draft schema as an upstream PACE format. The dependency +must supply a versioned project contract, validation diagnostics with object IDs, +an asset-loading contract, and a runnable web target before runtime integration +can be completed. + +1. Set `runtime.lock.json.runtime_revision` to the actual immutable core commit. +2. Add the core crate using `git` + `rev` (and commit Cargo.lock), or pin its WASM + artifact with a checksum. Never use a moving branch in shipped exports. +3. Add a separate conversion adapter from `model::Project` to the core model. + Check all conversions; report unsupported fields on their owning object. +4. Test a canonical core three-room fixture against that pinned loader, including + assets, room transitions, conditional item actions and branching dialogue. +5. Route both preview and export through that same loader/runtime. Only then + enable core export. Export must contain the pinned runtime and all assets. +6. Keep a versioned draft migration path; do not silently rename old files into + the core format or discard fields the core version cannot represent. + +The three-room authoring example in this repository is editor-owned. Replace or +compare it with the canonical core fixture when the latter is available. diff --git a/fixtures/backgrounds/foyer.png b/fixtures/backgrounds/foyer.png new file mode 100644 index 0000000000000000000000000000000000000000..c1d3029a5f4bb5a15395b42db4cad9bf81a1b829 GIT binary patch literal 5622 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 literal 0 HcmV?d00001 diff --git a/runtime.lock.json b/runtime.lock.json new file mode 100644 index 0000000..d93276e --- /dev/null +++ b/runtime.lock.json @@ -0,0 +1,9 @@ +{ + "platform": "web-wasm", + "core_repository": "https://github.com/pace-kit/pace_core", + "inspected_core_revision": "6ccfd6ea60534f3c3312882458e1c83308a76b81", + "runtime_revision": null, + "status": "blocked: upstream contains no format or runtime API", + "editor_format": "pace-editor-draft", + "editor_format_version": 1 +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..4b46634 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,5 @@ +[toolchain] +channel = "1.90.0" +components = ["rustfmt", "clippy"] +targets = ["wasm32-unknown-unknown"] +profile = "minimal" diff --git a/web_view/Cargo.toml b/web_view/Cargo.toml index ab4058d..e074527 100644 --- a/web_view/Cargo.toml +++ b/web_view/Cargo.toml @@ -1,24 +1,8 @@ [package] name = "web_view" version = "0.1.0" -authors = ["WilliamRagstad "] edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] - app = { path = "../app", features = ["web"] } - -serde = { version = "1.0.197", features = ["derive"] } - -dioxus = { version = "0.5", features = ["fullstack", "router"] } - -# Debug -tracing = "0.1.40" -dioxus-logger = "0.5.0" - -[features] -default = [] -server = ["dioxus/axum"] -web = ["dioxus/web"] +dioxus = { version = "=0.5.6", default-features = false, features = ["web", "launch"] } diff --git a/web_view/index.html b/web_view/index.html new file mode 100644 index 0000000..6a738a7 --- /dev/null +++ b/web_view/index.html @@ -0,0 +1,11 @@ + + + + + + + PACE — Adventure editor + + +
+ diff --git a/web_view/src/main.rs b/web_view/src/main.rs index c662a34..5edaaf9 100644 --- a/web_view/src/main.rs +++ b/web_view/src/main.rs @@ -1,10 +1,3 @@ -use tracing::Level; - -use app::App; - fn main() { - // Init logger - dioxus_logger::init(Level::INFO).expect("failed to init logger"); - - dioxus::launch(App); + dioxus::launch(app::App); } From 61042ac08649a936734106d2eea587198df234b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20R=C3=A5gstad?= Date: Sun, 25 Oct 2026 13:24:52 +0000 Subject: [PATCH 2/3] feat: add background import and room hotspot editing tools --- README.md | 25 +++++ app/Cargo.toml | 2 +- app/src/browser.rs | 20 ++++ app/src/editor/mod.rs | 4 + app/src/lib.rs | 1 + app/src/model.rs | 6 +- app/src/rooms.rs | 237 ++++++++++++++++++++++++++++++++++++++++ app/src/ui.rs | 12 +- app/tests/project.rs | 68 ++++++++++++ package-lock.json | 76 +++++++++++++ package.json | 6 + playwright.config.ts | 15 +++ tests/e2e/rooms.spec.ts | 68 ++++++++++++ 13 files changed, 533 insertions(+), 7 deletions(-) create mode 100644 app/src/rooms.rs create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 playwright.config.ts create mode 100644 tests/e2e/rooms.spec.ts diff --git a/README.md b/README.md index c2fa040..bef391b 100644 --- a/README.md +++ b/README.md @@ -52,3 +52,28 @@ Save downloads the full project and attempts an atomic browser recovery copy. Recovery is origin-specific and limited by browser quota; a warning instructs you to save a file if it is unavailable. Project files are the portable source of truth. Keep a downloaded copy before clearing browser data. + +## Room tools + +Add a room and import its background. Use **Draw hotspot** to drag a rectangle +in either direction, or **Add hotspot** for keyboard-friendly placement. Drag a +selected hotspot to move it; arrow keys nudge it by 1% of the image. Set exact +X/Y/width/height percentages in the inspector. Image replacement preserves the +normalized bounds. A **Go to room** action links to a stable room ID, so renaming +a destination does not break the link. Add a separate return hotspot for a +bidirectional connection. + +Validation entries identify the object ID and field; click an entry to select +its room, hotspot, item, or dialogue. Saves may contain incomplete drafts. +Invalid drafts cannot be rehearsed. + +## Browser checks + +```sh +npm ci +npx playwright install --with-deps chromium +trunk build +npm run test:e2e +``` + +For an existing Chromium installation, set `CHROMIUM_PATH=/usr/bin/chromium`. diff --git a/app/Cargo.toml b/app/Cargo.toml index 1833d4b..d0e407b 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] dioxus = { version = "=0.5.6", default-features = false, features = ["macro", "html", "signals", "hooks"] } -serde = { version = "1", features = ["derive"] } +serde = { version = "1", features = ["derive", "rc"] } serde_json = "1" base64 = "0.22" imagesize = "0.13" diff --git a/app/src/browser.rs b/app/src/browser.rs index 6fe1e46..7e0d06c 100644 --- a/app/src/browser.rs +++ b/app/src/browser.rs @@ -58,6 +58,21 @@ mod web { } Ok(()) } + pub fn capture_pointer(id: i32) { + if let Some(element) = web_sys::window() + .and_then(|w| w.document()) + .and_then(|d| d.get_element_by_id("room-stage")) + { + let _ = element.set_pointer_capture(id); + } + } + #[wasm_bindgen::prelude::wasm_bindgen( + inline_js = "export function setDirty(dirty) { window.onbeforeunload = dirty ? (event) => { event.preventDefault(); event.returnValue = ''; } : null; }" + )] + extern "C" { + #[wasm_bindgen::prelude::wasm_bindgen(js_name = setDirty)] + pub fn set_dirty(dirty: bool); + } pub fn stage_point(x: f64, y: f64) -> Option<(f64, f64)> { let rect = web_sys::window()? .document()? @@ -94,3 +109,8 @@ pub fn download(_: &str) -> Result<(), String> { pub fn stage_point(_: f64, _: f64) -> Option<(f64, f64)> { None } + +#[cfg(not(target_arch = "wasm32"))] +pub fn capture_pointer(_: i32) {} +#[cfg(not(target_arch = "wasm32"))] +pub fn set_dirty(_: bool) {} diff --git a/app/src/editor/mod.rs b/app/src/editor/mod.rs index a691e79..52b6ebb 100644 --- a/app/src/editor/mod.rs +++ b/app/src/editor/mod.rs @@ -1,4 +1,6 @@ use crate::model::Project; +use std::sync::atomic::{AtomicUsize, Ordering}; +static NEXT_DOCUMENT: AtomicUsize = AtomicUsize::new(1); #[derive(Clone, Debug, PartialEq, Eq)] pub enum Selection { @@ -11,6 +13,7 @@ pub enum Selection { #[derive(Clone)] pub struct Editor { + pub document_id: usize, pub project: Project, pub selection: Selection, pub dirty: bool, @@ -32,6 +35,7 @@ impl Editor { .map(|r| Selection::Room(r.id.clone())) .unwrap_or(Selection::Project); Self { + document_id: NEXT_DOCUMENT.fetch_add(1, Ordering::Relaxed), project, selection, dirty: false, diff --git a/app/src/lib.rs b/app/src/lib.rs index e34be3a..8a49e4a 100644 --- a/app/src/lib.rs +++ b/app/src/lib.rs @@ -2,5 +2,6 @@ mod browser; pub mod editor; pub mod model; +mod rooms; mod ui; pub use ui::App; diff --git a/app/src/model.rs b/app/src/model.rs index 1101d36..7c9454d 100644 --- a/app/src/model.rs +++ b/app/src/model.rs @@ -2,7 +2,7 @@ //! format: the inspected upstream revision has no serializable model or runtime. use base64::{engine::general_purpose::STANDARD, Engine}; use serde::{Deserialize, Serialize}; -use std::collections::HashSet; +use std::{collections::HashSet, sync::Arc}; pub const FORMAT: &str = "pace-editor-draft"; pub const VERSION: u32 = 1; @@ -35,7 +35,7 @@ pub struct Room { #[serde(deny_unknown_fields)] pub struct Background { pub name: String, - pub data_url: String, + pub data_url: Arc, pub width: u32, pub height: u32, } @@ -420,7 +420,7 @@ impl Background { } Ok(Self { name, - data_url: format!("data:{mime};base64,{}", STANDARD.encode(bytes)), + data_url: format!("data:{mime};base64,{}", STANDARD.encode(bytes)).into(), width: size.width as u32, height: size.height as u32, }) diff --git a/app/src/rooms.rs b/app/src/rooms.rs new file mode 100644 index 0000000..a46d062 --- /dev/null +++ b/app/src/rooms.rs @@ -0,0 +1,237 @@ +use crate::{ + browser, + editor::{Editor, Selection}, + model::{Action, Background, Hotspot, Rect, Room}, +}; +use dioxus::prelude::*; + +pub fn update_room(mut editor: Signal, change: impl FnOnce(&mut Room)) { + let id = editor.read().selected_room().map(str::to_owned); + if let Some(id) = id { + editor.write().edit(|p| { + if let Some(r) = p.room_mut(&id) { + change(r); + } + }); + } +} +pub fn update_hotspot(mut editor: Signal, change: impl FnOnce(&mut Hotspot)) { + let selection = editor.read().selection.clone(); + if let Selection::Hotspot(room_id, id) = selection { + editor.write().edit(|p| { + if let Some(h) = p + .room_mut(&room_id) + .and_then(|r| r.hotspots.iter_mut().find(|h| h.id == id)) + { + change(h); + } + }); + } +} +fn position(rect: Rect) -> String { + format!( + "left:{}%;top:{}%;width:{}%;height:{}%", + rect.x * 100., + rect.y * 100., + rect.width * 100., + rect.height * 100. + ) +} +#[derive(Clone)] +enum Drag { + Draw { + start: (f64, f64), + end: (f64, f64), + }, + Move { + id: String, + start: (f64, f64), + end: (f64, f64), + original: Rect, + }, +} +impl Drag { + fn rect(&self) -> Option { + match self { + Self::Draw { start, end } => Rect::from_drag(*start, *end), + Self::Move { + start, + end, + original, + .. + } => Some(original.translated(end.0 - start.0, end.1 - start.1)), + } + } + fn set_end(&mut self, point: (f64, f64)) { + match self { + Self::Draw { end, .. } | Self::Move { end, .. } => *end = point, + } + } +} + +#[component] +pub fn RoomWorkspace(mut editor: Signal, mut notice: Signal) -> Element { + let mut drawing = use_signal(|| false); + let mut drag: Signal> = use_signal(|| None); + let room = editor + .read() + .selected_room() + .and_then(|id| editor.read().project.room(id).cloned()); + let Some(room) = room else { + return rsx! { div { class: "empty-state", span { class: "empty-icon", "◇" } h1 { "Every adventure starts somewhere." } p { "Add a room, import its background, and bring your world to life." } } }; + }; + let selected_id = match &editor.read().selection { + Selection::Hotspot(_, id) => Some(id.clone()), + _ => None, + }; + let dimensions = room + .background + .as_ref() + .map(|b| format!("{} × {}", b.width, b.height)) + .unwrap_or_default(); + rsx! { + div { class: "room-heading", div { h1 { "{room.name}" } p { "Set the scene. Give every detail a story." } } + label { class: "button", "Import background" + input { r#type: "file", accept: "image/png,image/jpeg,image/webp", "aria-label": "Import background", onchange: move |event: Event| async move { + let room_id = editor.read().selected_room().map(str::to_owned); + let document_id = editor.read().document_id; + if let (Some(files), Some(room_id)) = (event.files(), room_id) { + if let Some(name) = files.files().first() { + match files.read_file(name).await { + Some(_) if editor.read().document_id != document_id => notice.set("Image import cancelled because a different project was opened.".into()), + Some(bytes) => match Background::import(name.clone(), &bytes) { + Ok(background) => { editor.write().edit(|p| { if let Some(room) = p.room_mut(&room_id) { room.background = Some(background); } }); notice.set("Background imported. Hotspot bounds scale with the image.".into()); }, + Err(e) => notice.set(e), + }, + None => notice.set("Cannot read this image.".into()), + } + } + } + } } + } + } + if let Some(background) = &room.background { + div { class: "segmented", + button { class: if !drawing() { "primary" } else { "" }, onclick: move |_| { drawing.set(false); drag.set(None); }, "Select / move" } + button { class: if drawing() { "primary" } else { "" }, onclick: move |_| { drawing.set(true); drag.set(None); }, "Draw hotspot" } + button { onclick: move |_| { + let room_id = editor.read().selected_room().map(str::to_owned); + if let Some(room_id) = room_id { let mut id = None; editor.write().edit(|p| id = p.add_hotspot(&room_id, Rect { x:0.35,y:0.35,width:0.2,height:0.2 })); if let Some(id) = id { editor.write().selection = Selection::Hotspot(room_id,id); } } + }, "Add hotspot" } + } + div { id: "room-stage", class: if drawing() { "stage drawing" } else { "stage" }, style: "aspect-ratio:{background.width}/{background.height}", "aria-label": "Room canvas", + onkeydown: move |event| { if event.key() == Key::Escape { drag.set(None); drawing.set(false); } }, + onpointerdown: move |event| { if drawing() && event.trigger_button() == Some(dioxus::html::input_data::MouseButton::Primary) { + let point = event.client_coordinates(); if let Some(point) = browser::stage_point(point.x,point.y) { browser::capture_pointer(event.pointer_id()); drag.set(Some(Drag::Draw {start:point,end:point})); } + } }, + onpointermove: move |event| { let point = event.client_coordinates(); if let Some(point) = browser::stage_point(point.x,point.y) { if let Some(drag) = drag.write().as_mut() { drag.set_end(point); } } }, + onpointercancel: move |_| drag.set(None), + onpointerup: move |_| { + let gesture = drag.write().take(); + if let Some(gesture) = gesture { if let Some(rect) = gesture.rect() { + let room_id = editor.read().selected_room().map(str::to_owned); + if let Some(room_id) = room_id { match gesture { + Drag::Draw {..} => { let mut id = None; editor.write().edit(|p| id = p.add_hotspot(&room_id,rect)); if let Some(id) = id { editor.write().selection = Selection::Hotspot(room_id,id); } drawing.set(false); }, + Drag::Move {id,..} => editor.write().edit(|p| { if let Some(h) = p.room_mut(&room_id).and_then(|r| r.hotspots.iter_mut().find(|h| h.id == id)) { h.rect = rect; } }), + } } + } } + }, + img { src: "{background.data_url}", alt: "{room.name} background", draggable: "false" } + for hotspot in room.hotspots.clone() { + HotspotButton { key: "{hotspot.id}", hotspot: hotspot.clone(), selected: selected_id.as_deref() == Some(&hotspot.id), editor, drag } + } + if let Some(rect) = drag.read().as_ref().and_then(Drag::rect) { div { class: "ghost", style: position(rect) } } + } + div { class: "stage-caption", span { "{dimensions} · Original image coordinates" } span { "{room.hotspots.len()} hotspots" } } + p { class: "muted", style: "margin-top:14px", "Draw a rectangle, drag to move, or use Add hotspot and edit its bounds. Escape cancels a gesture." } + } else { + div { class: "empty-state", span { class: "empty-icon", "▧" } h1 { "A place for your story." } p { "Import a PNG, JPEG, or WebP background to start placing hotspots." } p { class: "muted", "Up to 8 MiB per image. Images travel with your project." } } + } + if !room.hotspots.is_empty() { + div { class: "hotspot-list", h3 { "IN THIS ROOM" } + for hotspot in room.hotspots { + button { class: "hotspot-row", onclick: move |_| { + let room_id = editor.read().selected_room().map(str::to_owned); if let Some(room_id) = room_id { editor.write().selection = Selection::Hotspot(room_id,hotspot.id.clone()); } + }, "◇ {hotspot.name}" span { {match hotspot.action { Action::Look {..} => "INSPECT", Action::GoTo {..} => "GO TO ROOM", Action::Take {..} => "PICK UP ITEM", Action::Talk {..} => "DIALOGUE" }} } } + } + } + } + } +} + +#[component] +fn HotspotButton( + hotspot: Hotspot, + selected: bool, + mut editor: Signal, + mut drag: Signal>, +) -> Element { + let id = hotspot.id.clone(); + let key_id = id.clone(); + let click_id = id.clone(); + rsx! { button { class: if selected { "hotspot selected" } else { "hotspot" }, style: position(hotspot.rect), "aria-label": "Select hotspot {hotspot.name}", + onclick: move |_| { let room_id = editor.read().selected_room().map(str::to_owned); if let Some(room_id) = room_id { editor.write().selection = Selection::Hotspot(room_id,click_id.clone()); } }, + onpointerdown: move |event| { + event.stop_propagation(); + let room_id = editor.read().selected_room().map(str::to_owned); + if let Some(room_id) = room_id { editor.write().selection = Selection::Hotspot(room_id,id.clone()); } + let point = event.client_coordinates(); if let Some(point) = browser::stage_point(point.x,point.y) { browser::capture_pointer(event.pointer_id()); drag.set(Some(Drag::Move { id:id.clone(),start:point,end:point,original:hotspot.rect })); } + }, + onkeydown: move |event| { + let delta = match event.key() { Key::ArrowLeft => Some((-0.01,0.)), Key::ArrowRight => Some((0.01,0.)), Key::ArrowUp => Some((0.,-0.01)), Key::ArrowDown => Some((0.,0.01)), Key::Escape => { drag.set(None); None }, _ => None }; + if let Some((dx,dy)) = delta { let room_id = editor.read().selected_room().map(str::to_owned); if let Some(room_id) = room_id { editor.write().edit(|p| { if let Some(h) = p.room_mut(&room_id).and_then(|r| r.hotspots.iter_mut().find(|h| h.id == key_id)) { h.rect = h.rect.translated(dx,dy); } }); } } + }, + "{hotspot.name}" + } } +} + +#[component] +pub fn RoomInspector(mut editor: Signal) -> Element { + let room = editor + .read() + .selected_room() + .and_then(|id| editor.read().project.room(id).cloned()); + let Some(room) = room else { + return rsx! {}; + }; + let hotspot = match &editor.read().selection { + Selection::Hotspot(_, id) => room.hotspots.iter().find(|h| &h.id == id).cloned(), + _ => None, + }; + if let Some(h) = hotspot { + let action = match h.action { + Action::Look { .. } => "look", + Action::GoTo { .. } => "go_to", + Action::Take { .. } => "take", + Action::Talk { .. } => "talk", + }; + rsx! { + h2 { "Hotspot" } p { class: "muted", "{h.id}" } + label { "Hotspot name" input { value: "{h.name}", oninput: move |e| update_hotspot(editor,|h| h.name = e.value()) } } + h3 { "BOUNDS · % OF IMAGE" } + div { class: "fields-grid", + for (field,value) in [("X",h.rect.x),("Y",h.rect.y),("Width",h.rect.width),("Height",h.rect.height)] { + label { "{field} (%)" input { r#type: "number", min: "0", max: "100", step: "0.1", value: format!("{:.2}",value*100.), oninput: move |e| { if let Ok(value) = e.value().parse::() { update_hotspot(editor, |h| match field { "X" => h.rect.x = value/100., "Y" => h.rect.y = value/100., "Width" => h.rect.width = value/100., _ => h.rect.height = value/100. }); } } } } + } + } + label { "Action" select { value: action, onchange: move |e| update_hotspot(editor, |h| h.action = match e.value().as_str() { "go_to" => Action::GoTo { room_id: String::new() }, "take" => Action::Take { item_id: String::new() }, "talk" => Action::Talk { dialogue_id: String::new() }, _ => Action::Look { text: String::new() } }), + option { value: "look", "Inspect" } option { value: "go_to", "Go to room" } option { value: "take", "Pick up item" } option { value: "talk", "Start dialogue" } + } } + match h.action { + Action::Look {text} => rsx! { label { "Inspection text" textarea { value: "{text}", oninput: move |e| update_hotspot(editor, |h| h.action = Action::Look { text:e.value() }) } } }, + Action::GoTo {room_id} => rsx! { label { "Destination room" select { value: "{room_id}", onchange: move |e| update_hotspot(editor, |h| h.action = Action::GoTo { room_id:e.value() }), option { value: "", "Choose destination" } for r in editor.read().project.rooms.clone() { option { value: "{r.id}", "{r.name}" } } } } }, + Action::Take {item_id} => rsx! { label { "Item to pick up" select { value: "{item_id}", onchange: move |e| update_hotspot(editor, |h| h.action = Action::Take { item_id:e.value() }), option { value: "", "Choose item" } for item in editor.read().project.items.clone() { option { value: "{item.id}", "{item.name}" } } } } }, + Action::Talk {dialogue_id} => rsx! { label { "Dialogue to start" select { value: "{dialogue_id}", onchange: move |e| update_hotspot(editor, |h| h.action = Action::Talk { dialogue_id:e.value() }), option { value: "", "Choose dialogue" } for d in editor.read().project.dialogues.clone() { option { value: "{d.id}", "{d.name}" } } } } }, + } + label { "Requires item" select { value: h.requires_item.clone().unwrap_or_default(), onchange: move |e| update_hotspot(editor, |h| h.requires_item = if e.value().is_empty() { None } else { Some(e.value()) }), option { value: "", "No requirement" } for item in editor.read().project.items.clone() { option { value: "{item.id}", "{item.name}" } } } } + p { class: "muted", "Room links are one-way. Add a return hotspot in the destination room." } + button { class: "danger", onclick: move |_| editor.write().delete_selection(), "Delete hotspot" } + } + } else { + rsx! { h2 { "Room" } p { class: "muted", "{room.id}" } + label { "Room name" input { value: "{room.name}", oninput: move |e| update_room(editor, |r| r.name = e.value()) } } + p { class: "muted", "Select a hotspot on the canvas or in the list to edit its action and bounds." } + button { class: "danger", onclick: move |_| { if browser::confirm("Delete this room and its hotspots? Links from other objects will be reported in validation. You can undo this.") { editor.write().delete_selection(); } }, "Delete room" } + } + } +} diff --git a/app/src/ui.rs b/app/src/ui.rs index 47b6ced..e5d4204 100644 --- a/app/src/ui.rs +++ b/app/src/ui.rs @@ -19,6 +19,7 @@ pub fn App() -> Element { } editor }); + use_effect(move || browser::set_dirty(editor.read().dirty)); let issues = editor.read().project.validate(); rsx! { style { {include_str!("editor.css")} } @@ -26,14 +27,17 @@ pub fn App() -> Element { header { class: "topbar", div { class: "brand", "P" } div { class: "brand-copy", strong { "PACE" } span { "Adventure editor" } } - div { class: "project-title", "{editor.read().project.title}" } + div { class: "project-title", "{editor.read().project.title}" if editor.read().dirty { span { title: "Changes not yet saved to file", " •" } } } button { onclick: move |_| { if !editor.read().dirty || browser::confirm("Discard changes that have not been saved to a project file?") { editor.set(Editor::default()); } }, "New project" } label { class: "button", "Open project" input { r#type: "file", accept: ".json", "aria-label": "Open project", onchange: move |event: Event| async move { if editor.read().dirty && !browser::confirm("Replace this project? Save a file first to keep your changes.") { return; } + let document_id = editor.read().document_id; + let original = editor.read().project.clone(); if let Some(files) = event.files() { if let Some(name) = files.files().first() { match files.read_file_to_string(name).await { + Some(_) if editor.read().document_id != document_id || editor.read().project != original => notice.set("Open cancelled because the project changed while the file was being read. Try opening it again.".into()), Some(text) => match editor.write().open(&text) { Ok(()) => notice.set("Project opened.".into()), Err(e) => notice.set(e) }, None => notice.set("Could not read project file.".into()), } @@ -64,16 +68,18 @@ pub fn App() -> Element { button { disabled: !editor.read().can_undo(), onclick: move |_| editor.write().undo(), "Undo" } button { disabled: !editor.read().can_redo(), onclick: move |_| editor.write().redo(), "Redo" } } - div { class: "empty-state", span { class: "empty-icon", "◇" } h1 { "Every adventure starts somewhere." } p { "Add a room, import its background, and bring your world to life." } } + crate::rooms::RoomWorkspace { key: "{editor.read().selected_room().unwrap_or_default()}", editor, notice } } aside { class: "inspector", + if editor.read().selected_room().is_some() { crate::rooms::RoomInspector { editor } } else { h2 { "Project" } label { "Project title" input { value: "{editor.read().project.title}", oninput: move |e| editor.write().edit(|p| p.title = e.value()) } } label { "Starting room" select { value: editor.read().project.start_room.clone().unwrap_or_default(), onchange: move |e| editor.write().edit(|p| p.start_room = if e.value().is_empty() { None } else { Some(e.value()) }), option { value: "", "Choose a room" } for room in editor.read().project.rooms.clone() { option { value: "{room.id}", "{room.name}" } } } } + } h3 { "Validation · {issues.len()}" } if issues.is_empty() { p { class: "success", "Ready for draft authoring." } } for issue in issues { - button { class: "issue", onclick: move |_| editor.write().focus(issue.object_id.as_deref()), strong { "{issue.field}" } span { "{issue.message}" } } + button { class: "issue", onclick: move |_| editor.write().focus(issue.object_id.as_deref()), strong { {format!("{} · {}", issue.object_id.as_deref().unwrap_or("Project"), issue.field)} } span { "{issue.message}" } } } } } diff --git a/app/tests/project.rs b/app/tests/project.rs index d9bed90..73352ab 100644 --- a/app/tests/project.rs +++ b/app/tests/project.rs @@ -136,3 +136,71 @@ fn import_rejects_unsupported_corrupt_or_oversize_images() { p.rooms[0].background.as_mut().unwrap().width += 1; assert!(p.validate().iter().any(|i| i.field == "background")); } +#[test] +fn canvas_geometry_handles_reverse_drag_clamping_and_tiny_gestures() { + assert_eq!( + Rect::from_drag((0.8, 0.9), (0.2, 0.3)).unwrap(), + Rect { + x: 0.2, + y: 0.3, + width: 0.6000000000000001, + height: 0.6000000000000001 + } + ); + let rect = Rect::from_drag((-1., -1.), (2., 2.)).unwrap(); + assert_eq!( + rect, + Rect { + x: 0., + y: 0., + width: 1., + height: 1. + } + ); + assert!(Rect::from_drag((0.5, 0.5), (0.5, 0.6)).is_none()); + assert!( + Rect { + x: f64::NAN, + y: 0., + width: 0.1, + height: 0.1 + } + .valid() + == false + ); + let moved = Rect { + x: 0.1, + y: 0.2, + width: 0.25, + height: 0.3, + } + .translated(2., -2.); + assert_eq!(moved.x, 0.75); + assert_eq!(moved.y, 0.); +} +#[test] +fn room_and_hotspot_operations_preserve_links_across_rename_and_report_deletion() { + let mut p = project(); + let destination = p.add_room(); + p.rooms[0].hotspots[1].action = Action::GoTo { + room_id: destination.clone(), + }; + p.room_mut(&destination).unwrap().name = "Renamed".into(); + assert!(!p.validate().iter().any(|i| i.field == "action.room_id")); + let affected = p.rooms[0].hotspots[1].id.clone(); + let mut e = Editor::new(p.clone()); + e.selection = Selection::Room(destination); + e.delete_selection(); + assert!(e + .project + .validate() + .iter() + .any(|i| i.object_id == Some(affected.clone()) && i.field == "action.room_id")); + e.focus(Some(&affected)); + assert_eq!( + e.selection, + Selection::Hotspot(p.rooms[0].id.clone(), affected) + ); + e.undo(); + assert_eq!(e.project, p); +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ea46827 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,76 @@ +{ + "name": "pace-editor-browser-tests", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "pace-editor-browser-tests", + "devDependencies": { + "@playwright/test": "1.56.1" + } + }, + "node_modules/@playwright/test": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz", + "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.56.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.56.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..429ce01 --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "name": "pace-editor-browser-tests", + "private": true, + "scripts": { "test:e2e": "playwright test" }, + "devDependencies": { "@playwright/test": "1.56.1" } +} diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..4806be4 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from '@playwright/test'; +export default defineConfig({ + testDir: './tests/e2e', + fullyParallel: false, + workers: 1, + use: { + baseURL: 'http://127.0.0.1:8080', + actionTimeout: 10_000, + viewport: { width: 1440, height: 1000 }, + launchOptions: process.env.CHROMIUM_PATH ? { executablePath: process.env.CHROMIUM_PATH } : {}, + trace: 'retain-on-failure', + screenshot: 'only-on-failure', + }, + webServer: { command: 'python3 -m http.server 8080 --bind 127.0.0.1 --directory dist', url: 'http://127.0.0.1:8080', reuseExistingServer: !process.env.CI }, +}); diff --git a/tests/e2e/rooms.spec.ts b/tests/e2e/rooms.spec.ts new file mode 100644 index 0000000..afdcb17 --- /dev/null +++ b/tests/e2e/rooms.spec.ts @@ -0,0 +1,68 @@ +import { test, expect } from '@playwright/test'; +import fs from 'node:fs/promises'; + +test('import, draw, move, link, validate, undo, save and reopen rooms', async ({ page }, testInfo) => { + const errors: string[] = []; + page.on('pageerror', error => errors.push(error.message)); + page.on('dialog', dialog => dialog.accept()); + await page.goto('/'); + await page.getByRole('button', { name: 'Add room', exact: true }).click(); + await page.getByLabel('Room name', { exact: true }).fill('Foyer'); + await page.getByLabel('Import background', { exact: true }).setInputFiles('fixtures/backgrounds/foyer.png'); + await expect(page.getByRole('img', { name: 'Foyer background' })).toBeVisible(); + await page.getByRole('button', { name: 'Draw hotspot', exact: true }).click(); + const canvas = await page.locator('#room-stage').boundingBox(); + if (!canvas) throw new Error('Missing canvas'); + await page.mouse.move(canvas.x + canvas.width * .3, canvas.y + canvas.height * .7); + await page.mouse.down(); + await page.mouse.move(canvas.x + canvas.width * .1, canvas.y + canvas.height * .2, { steps: 8 }); + await page.mouse.up(); + await page.getByLabel('Hotspot name', { exact: true }).fill('Study door'); + const drawnX = Number(await page.getByLabel('X (%)', { exact: true }).inputValue()); + expect(Math.abs(drawnX - 10)).toBeLessThan(.2); + expect(Math.abs(Number(await page.getByLabel('Width (%)', { exact: true }).inputValue()) - 20)).toBeLessThan(.2); + await page.getByRole('button', { name: 'Select hotspot Study door', exact: true }).press('ArrowRight'); + await expect(page.getByLabel('X (%)', { exact: true })).toHaveValue((drawnX + 1).toFixed(2)); + await page.getByRole('button', { name: 'Undo', exact: true }).click(); + await expect(page.getByLabel('X (%)', { exact: true })).toHaveValue(drawnX.toFixed(2)); + await page.getByRole('button', { name: 'Add room', exact: true }).click(); + await page.getByLabel('Room name', { exact: true }).fill('Study'); + await page.getByLabel('Import background', { exact: true }).setInputFiles('fixtures/backgrounds/study.png'); + await expect(page.getByRole('img', { name: 'Study background' })).toBeVisible(); + await page.getByRole('button', { name: 'Foyer', exact: true }).click(); + await page.getByRole('button', { name: 'Select hotspot Study door', exact: true }).click(); + await page.getByRole('combobox', { name: 'Action', exact: true }).selectOption('go_to'); + await page.getByRole('combobox', { name: 'Destination room', exact: true }).selectOption({ label: 'Study' }); + await expect(page.getByText('Validation · 0', { exact: true })).toBeVisible(); + await page.getByRole('button', { name: 'Study', exact: true }).click(); + await page.getByRole('button', { name: 'Delete room', exact: true }).click(); + await page.locator('.issue').filter({ hasText: 'action.room_id' }).click(); + await expect(page.getByLabel('Hotspot name', { exact: true })).toHaveValue('Study door'); + await page.getByRole('button', { name: 'Undo', exact: true }).click(); + await expect(page.getByText('Validation · 0', { exact: true })).toBeVisible(); + const downloadPromise = page.waitForEvent('download'); + await page.getByRole('button', { name: 'Save project', exact: true }).click(); + const download = await downloadPromise; + const file = testInfo.outputPath('rooms.pace-draft.json'); + await download.saveAs(file); + const saved = JSON.parse(await fs.readFile(file, 'utf8')); + expect(saved.rooms).toHaveLength(2); + expect(saved.rooms[0].hotspots[0].action.room_id).toBe(saved.rooms[1].id); + expect(saved.rooms[0].background.data_url).toMatch(/^data:image\/png;base64,/); + await page.getByRole('button', { name: 'New project', exact: true }).click(); + await page.getByLabel('Open project', { exact: true }).setInputFiles(file); + await expect(page.getByRole('heading', { name: 'Foyer', exact: true })).toBeVisible(); + const secondPromise = page.waitForEvent('download'); + await page.getByRole('button', { name: 'Save project', exact: true }).click(); + const second = await secondPromise; + await second.saveAs(testInfo.outputPath('roundtrip.json')); + expect(JSON.parse(await fs.readFile(testInfo.outputPath('roundtrip.json'), 'utf8'))).toEqual(saved); + await page.reload(); + await expect(page.getByRole('heading', { name: 'Foyer', exact: true })).toBeVisible(); + const malformed = testInfo.outputPath('unsupported.json'); + await fs.writeFile(malformed, JSON.stringify({ ...saved, version: 999 })); + await page.getByLabel('Open project', { exact: true }).setInputFiles(malformed); + await expect(page.getByRole('status')).toContainText('Unsupported draft version'); + await expect(page.getByRole('heading', { name: 'Foyer', exact: true })).toBeVisible(); + expect(errors).toEqual([]); +}); From f596ad917b52b1ddc8c2ad3bbf2f9340a951f55a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20R=C3=A5gstad?= Date: Sun, 25 Oct 2026 13:38:00 +0000 Subject: [PATCH 3/3] feat: add dialogue inventory and isolated draft rehearsal --- .github/workflows/editor.yml | 43 ++++++ README.md | 18 +++ app/src/browser.rs | 7 +- app/src/editor.css | 2 + app/src/lib.rs | 4 + app/src/model.rs | 31 ++++- app/src/preview.rs | 47 +++++++ app/src/rehearsal.rs | 120 +++++++++++++++++ app/src/rooms.rs | 20 +-- app/src/story.rs | 102 ++++++++++++++ app/src/ui.rs | 32 ++++- app/tests/project.rs | 31 +++-- app/tests/rehearsal.rs | 90 +++++++++++++ docs/images/01-room-editor.png | Bin 0 -> 123990 bytes docs/images/02-dialogue-editor.png | Bin 0 -> 116459 bytes docs/images/03-draft-rehearsal.png | Bin 0 -> 74961 bytes docs/walkthrough.md | 122 +++++++++++++++++ fixtures/three-rooms.pace-draft.json | 191 +++++++++++++++++++++++++++ tests/e2e/authoring.spec.ts | 132 ++++++++++++++++++ tests/e2e/recovery.spec.ts | 29 ++++ tests/e2e/rooms.spec.ts | 16 +++ web_view/index.html | 1 + 22 files changed, 1013 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/editor.yml create mode 100644 app/src/preview.rs create mode 100644 app/src/rehearsal.rs create mode 100644 app/src/story.rs create mode 100644 app/tests/rehearsal.rs create mode 100644 docs/images/01-room-editor.png create mode 100644 docs/images/02-dialogue-editor.png create mode 100644 docs/images/03-draft-rehearsal.png create mode 100644 docs/walkthrough.md create mode 100644 fixtures/three-rooms.pace-draft.json create mode 100644 tests/e2e/authoring.spec.ts create mode 100644 tests/e2e/recovery.spec.ts diff --git a/.github/workflows/editor.yml b/.github/workflows/editor.yml new file mode 100644 index 0000000..8e91fbf --- /dev/null +++ b/.github/workflows/editor.yml @@ -0,0 +1,43 @@ +name: Web editor +on: + push: + pull_request: +permissions: + contents: read +jobs: + editor: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: '1.90.0' + targets: wasm32-unknown-unknown + components: rustfmt, clippy + - uses: Swatinem/rust-cache@v2 + - run: cargo fmt --all -- --check + - run: cargo test --workspace --locked + - run: cargo clippy --workspace --all-targets --locked -- -D warnings + - run: cargo check -p web_view --target wasm32-unknown-unknown --locked + - uses: taiki-e/install-action@v2 + with: + tool: trunk@0.21.14 + - run: trunk build --release --locked + env: + NO_COLOR: 'true' + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: npm + - run: npm ci + - run: npx playwright install --with-deps chromium + - run: npm run test:e2e + - uses: actions/upload-artifact@v4 + if: always() + with: + name: browser-test-results + path: test-results/ + - uses: actions/upload-artifact@v4 + with: + name: pace-web-editor + path: dist/ diff --git a/README.md b/README.md index bef391b..9e44192 100644 --- a/README.md +++ b/README.md @@ -77,3 +77,21 @@ npm run test:e2e ``` For an existing Chromium installation, set `CHROMIUM_PATH=/usr/bin/chromium`. + +## Dialogue, inventory, and walkthrough + +Create inventory definitions and dialogue nodes from their sidebar sections. +Dialogue choices can branch to another node, grant an item, or end the +conversation. Hotspots can inspect text, link rooms, pick up an item, or start a +dialogue; any action can require an inventory item. Names are editable while IDs +stay stable. + +Follow [the illustrated walkthrough](docs/walkthrough.md) to author **The Garden +Key**, a three-room example, using only the editor controls. The browser test +reproduces the walkthrough, including save/reopen equality for the whole project. + +**Rehearse draft** runs an isolated editor simulation to exercise the draft's +links, dialogue branches and item gates. Restart clears its session. It never +modifies the source project and is **not** the PACE core runtime. **Core preview** +and **Export game** remain disabled. This implementation does not yet meet the +core-format serialization or pinned-runtime preview/export requirements. diff --git a/app/src/browser.rs b/app/src/browser.rs index 7e0d06c..33e1291 100644 --- a/app/src/browser.rs +++ b/app/src/browser.rs @@ -67,11 +67,13 @@ mod web { } } #[wasm_bindgen::prelude::wasm_bindgen( - inline_js = "export function setDirty(dirty) { window.onbeforeunload = dirty ? (event) => { event.preventDefault(); event.returnValue = ''; } : null; }" + inline_js = "export function setDirty(dirty) { window.onbeforeunload = dirty ? (event) => { event.preventDefault(); event.returnValue = ''; } : null; } export function openRehearsal() { const dialog = document.getElementById('draft-rehearsal'); if (!dialog) return; dialog.oncancel = event => { event.preventDefault(); dialog.querySelector('#close-rehearsal').click(); }; dialog.showModal(); }" )] extern "C" { #[wasm_bindgen::prelude::wasm_bindgen(js_name = setDirty)] pub fn set_dirty(dirty: bool); + #[wasm_bindgen::prelude::wasm_bindgen(js_name = openRehearsal)] + pub fn open_rehearsal(); } pub fn stage_point(x: f64, y: f64) -> Option<(f64, f64)> { let rect = web_sys::window()? @@ -114,3 +116,6 @@ pub fn stage_point(_: f64, _: f64) -> Option<(f64, f64)> { pub fn capture_pointer(_: i32) {} #[cfg(not(target_arch = "wasm32"))] pub fn set_dirty(_: bool) {} + +#[cfg(not(target_arch = "wasm32"))] +pub fn open_rehearsal() {} diff --git a/app/src/editor.css b/app/src/editor.css index 2ccc8dd..967ae5c 100644 --- a/app/src/editor.css +++ b/app/src/editor.css @@ -1 +1,3 @@ :root{font-family:'DM Sans',system-ui,sans-serif;color:#263d3c;background:#f5f6f3;font-synthesis:none;font-size:14px}*{box-sizing:border-box}body{margin:0}button,input,select,textarea{font:inherit}button,.button{display:inline-flex;align-items:center;justify-content:center;gap:6px;border:1px solid #d9dfda;background:#fff;color:#263d3c;border-radius:7px;padding:9px 13px;cursor:pointer;text-decoration:none;font-weight:600}button:hover,.button:hover{background:#edf2e9;border-color:#9cae9d}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,.stage:focus-visible{outline:3px solid #85b2ea;outline-offset:2px}button:disabled{opacity:.45;cursor:not-allowed}.primary{background:#224c43;color:#fff;border-color:#224c43}.primary:hover{background:#16392f}.button input[type=file]{position:absolute;width:1px;height:1px;opacity:0}.button:focus-within{outline:3px solid #85b2ea}h1,h2,h3,p{margin:0}h1,h2,h3{font-family:Manrope,system-ui,sans-serif}h2{font-size:17px}h3{font-size:12px;letter-spacing:.06em;margin:24px 0 12px}p{line-height:1.65;color:#6d7d76}label{display:flex;flex-direction:column;gap:7px;font-size:12px;font-weight:600;margin:16px 0}input:not([type=file]),select,textarea{width:100%;padding:10px;border:1px solid #d9dfda;border-radius:6px;background:#fff;color:#263d3c}textarea{min-height:90px;resize:vertical}.app{display:flex;flex-direction:column;min-height:100vh}.topbar{height:76px;display:flex;align-items:center;gap:12px;padding:0 24px;background:#fff;border-bottom:1px solid #e1e6e0}.brand{font-family:Manrope,sans-serif;font-weight:800;background:#224c43;color:#d9e8aa;width:38px;height:42px;border-radius:12px 12px 12px 2px;font-size:27px;text-align:center;padding-top:2px}.brand-copy{display:flex;flex-direction:column;gap:2px}.brand-copy strong{font-size:16px;letter-spacing:.13em}.brand-copy span{font-size:10px;color:#78867f}.project-title{margin:auto;font-weight:600}.dependency-banner{font-size:11px;padding:9px 24px;background:#edf0df;color:#69734b;border-bottom:1px solid #dfe3ce}.workspace{display:grid;grid-template-columns:220px minmax(320px,1fr) 290px;flex:1;min-height:calc(100vh - 149px)}.sidebar{background:#f9faf7;border-right:1px solid #e0e5dc;padding:24px 14px;display:flex;flex-direction:column}.section-heading{display:flex;align-items:center;justify-content:space-between;margin:28px 10px 12px}.section-heading h2{font-family:inherit;font-size:10px;letter-spacing:.12em;color:#849087}.section-heading button{padding:0;border:0;background:none;font-size:21px}.project-link{justify-content:flex-start;background:none;border:0;font-size:12px}.tree-row{display:flex;justify-content:flex-start;gap:9px;text-align:left;width:100%;border:0;background:none;margin:3px 0;padding:12px}.tree-row.active{background:#e8eddf;color:#234b40}.sidebar-foot{margin-top:auto;padding:48px 10px 0;font-size:11px;color:#849087;line-height:1.5}.main-panel{padding:20px 28px;min-width:0;background:radial-gradient(#dce3d9 .7px,transparent .7px);background-size:16px 16px}.toolbar{display:flex;align-items:center;gap:8px;margin-bottom:24px}.eyebrow{margin-right:auto;color:#859086;font-size:10px;letter-spacing:.12em;font-weight:700}.toolbar button{font-size:11px;padding:7px 11px}.empty-state{padding:90px 20px;text-align:center;max-width:530px;margin:auto}.empty-state h1{font-size:25px;line-height:1.5;margin:18px 0 12px}.empty-icon{display:inline-flex;align-items:center;justify-content:center;font-size:52px;width:90px;height:90px;border-radius:50%;background:#e5ecdd;color:#506c4a}.inspector{padding:26px 22px;background:#fff;border-left:1px solid #e0e5dc;overflow-wrap:anywhere}.issue{display:flex;flex-direction:column;align-items:flex-start;text-align:left;width:100%;font-size:11px;background:#fff8ef;border-color:#f1dfc5;color:#805d28;margin:8px 0;line-height:1.5}.issue span{font-weight:400}.success{color:#357350;font-size:12px}footer{min-height:36px;background:#fff;border-top:1px solid #e0e5dc;padding:9px 24px;font-size:11px;color:#64756c}.muted{font-size:11px;color:#829087;line-height:1.5}.danger{color:#a4473d;border-color:#e9d2cb;margin-top:18px}.room-heading{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px}.room-heading h1{font-size:25px}.room-heading p{font-size:12px;margin-top:6px}.stage{position:relative;box-shadow:0 12px 40px #263d3c18;background:#e2e8df;border-radius:8px;overflow:hidden;user-select:none;touch-action:none}.stage>img{display:block;width:100%;height:100%;pointer-events:none;object-fit:fill}.hotspot{position:absolute;background:#e5f29530;border:2px solid #e5f295;border-radius:3px;padding:0;color:#fff;text-shadow:0 1px 3px #000;font-size:11px;overflow:hidden;min-width:0}.hotspot:hover,.hotspot.selected{background:#e5f29555;border-color:#fff}.stage.drawing .hotspot{pointer-events:none}.ghost{position:absolute;border:2px dashed #fff;background:#e5f29555;pointer-events:none}.stage-caption{display:flex;justify-content:space-between;font-size:11px;color:#829087;margin-top:14px}.hotspot-list{margin-top:30px}.hotspot-row{display:flex;gap:12px;align-items:center;background:#fff;border:1px solid #e1e6dc;border-radius:7px;margin:7px 0;padding:12px;width:100%;text-align:left;font-size:12px;justify-content:flex-start}.hotspot-row span{margin-left:auto;color:#849087;font-size:10px}.fields-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 12px}.fields-grid label{margin:8px 0}.segmented{display:flex;gap:7px;margin:16px 0}.segmented button{font-size:11px}.card{background:#fff;border:1px solid #e1e6dc;border-radius:10px;padding:24px;margin-bottom:18px}.choice{padding:14px;background:#f6f8f1;border-radius:8px;margin:14px 0}.preview-overlay{position:fixed;inset:0;z-index:20;background:#132624e8;display:flex;align-items:center;justify-content:center;padding:24px}.preview{background:#f8f9f4;border-radius:12px;padding:24px;width:min(960px,95vw);max-height:95vh;overflow:auto}.preview .stage{max-height:56vh}.preview-head{display:flex;align-items:center;gap:12px;margin-bottom:16px}.preview-head h2{margin-right:auto}.inventory{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:16px 0;font-size:12px}.chip{background:#e6eddb;padding:7px 11px;border-radius:20px}.dialogue{padding:18px;background:#fff;border:1px solid #d9dfda;border-radius:8px}.dialogue p{margin:8px 0 14px}.dialogue button{margin-right:8px}.preview-note{font-size:11px;color:#93734e;margin:10px 0}.error{color:#a4473d}.inline-actions{display:flex;gap:8px;flex-wrap:wrap}@media(max-width:1050px){.workspace{grid-template-columns:180px minmax(280px,1fr) 250px}.main-panel{padding:18px}.topbar{gap:8px;padding:0 15px}.project-title{font-size:12px}.brand-copy span{display:none}}@media(max-width:760px){.workspace{grid-template-columns:150px 1fr}.inspector{grid-column:1/-1;border-top:1px solid #e0e5dc}.topbar{height:auto;min-height:76px;flex-wrap:wrap;padding:12px}.project-title{flex:1}.brand-copy{display:none}.topbar button,.topbar .button{font-size:11px}.sidebar{padding:12px 6px}.main-panel{padding:14px}.room-heading{align-items:flex-start;gap:8px}.toolbar{flex-wrap:wrap}.eyebrow{width:100%}.empty-state{padding:40px 10px}} + +.preview-overlay{width:100vw;height:100vh;max-width:none;max-height:none;border:0;margin:0;color:inherit}.preview-overlay::backdrop{background:transparent} diff --git a/app/src/lib.rs b/app/src/lib.rs index 8a49e4a..d4304c5 100644 --- a/app/src/lib.rs +++ b/app/src/lib.rs @@ -5,3 +5,7 @@ pub mod model; mod rooms; mod ui; pub use ui::App; + +mod preview; +pub mod rehearsal; +mod story; diff --git a/app/src/model.rs b/app/src/model.rs index 7c9454d..6112864 100644 --- a/app/src/model.rs +++ b/app/src/model.rs @@ -154,6 +154,16 @@ impl Default for Project { impl Project { pub fn to_json(&self) -> Result { + if self.rooms.iter().flat_map(|r| &r.hotspots).any(|h| { + [h.rect.x, h.rect.y, h.rect.width, h.rect.height] + .iter() + .any(|n| !n.is_finite()) + }) { + return Err( + "Cannot save a hotspot with non-finite coordinates. Correct its bounds first." + .into(), + ); + } let text = serde_json::to_string_pretty(self).map_err(|e| e.to_string())?; if text.len() > MAX_PROJECT_BYTES { return Err("Project exceeds the 64 MiB file limit. Reduce background sizes.".into()); @@ -287,10 +297,10 @@ impl Project { if self.title.trim().is_empty() { push(None, "title", "Give the project a title.".into()); } - if !self + if self .start_room .as_deref() - .is_some_and(|id| self.room(id).is_some()) + .is_none_or(|id| self.room(id).is_none()) { push( None, @@ -400,6 +410,23 @@ impl Project { } impl Background { + /// Only embedded raster data is rendered; malformed imports cannot load a + /// remote URL or an active document through the image element. + pub fn display_url(&self) -> &str { + if [ + "data:image/png;base64,", + "data:image/jpeg;base64,", + "data:image/webp;base64,", + ] + .iter() + .any(|prefix| self.data_url.starts_with(prefix)) + { + &self.data_url + } else { + "" + } + } + pub fn import(name: String, bytes: &[u8]) -> Result { if bytes.len() > MAX_IMAGE_BYTES { return Err("Background exceeds 8 MiB. Resize it before importing.".into()); diff --git a/app/src/preview.rs b/app/src/preview.rs new file mode 100644 index 0000000..a09f37b --- /dev/null +++ b/app/src/preview.rs @@ -0,0 +1,47 @@ +use crate::rehearsal::Rehearsal; +use dioxus::prelude::*; + +#[component] +pub fn DraftPreview(mut session: Signal>) -> Element { + use_effect(crate::browser::open_rehearsal); + let state = session.read().clone()?; + let room = state.project.room(&state.room_id)?; + let dialogue = state + .dialogue_id + .as_ref() + .and_then(|id| state.project.dialogues.iter().find(|d| &d.id == id)); + rsx! { + dialog { id: "draft-rehearsal", class: "preview-overlay", role: "dialog", "aria-modal": "true", "aria-label": "Draft rehearsal", + div { class: "preview", + div { class: "preview-head", h2 { "{room.name}" } + button { onclick: move |_| { let project = session.read().as_ref().map(|s| s.project.clone()); if let Some(p) = project { session.set(Rehearsal::new(&p).ok()); } }, "Restart" } + button { id: "close-rehearsal", autofocus: true, onclick: move |_| session.set(None), "Close rehearsal" } + } + p { class: "preview-note", "Editor rehearsal only · PACE runtime integration is pending. This does not verify runtime compatibility." } + if let Some(bg) = &room.background { + div { class: "stage", style: "aspect-ratio:{bg.width}/{bg.height}", + img { src: bg.display_url(), alt: "{room.name} background" } + for hotspot in room.hotspots.clone() { + button { class: "hotspot", disabled: dialogue.is_some(), style: format!("left:{}%;top:{}%;width:{}%;height:{}%",hotspot.rect.x*100.,hotspot.rect.y*100.,hotspot.rect.width*100.,hotspot.rect.height*100.), "aria-label": "Interact with {hotspot.name}", + onclick: move |_| { if let Some(state) = session.write().as_mut() { if let Err(e) = state.activate(&hotspot.id) { state.message = e; } } }, "{hotspot.name}" + } + } + } + } + div { class: "inventory", strong { "INVENTORY" } + if state.inventory.is_empty() { span { class: "muted", "Nothing collected yet" } } + for item in state.project.items.iter().filter(|i| state.inventory.contains(&i.id)) { span { class: "chip", title: "{item.description}", "{item.name}" } } + } + if let Some(d) = dialogue { + div { class: "dialogue", strong { "{d.speaker}" } p { "{d.text}" } + for choice in d.choices.clone() { + button { onclick: move |_| { if let Some(state) = session.write().as_mut() { if let Err(e) = state.choose(&choice.id) { state.message = e; } } }, "{choice.text}" } + } + if d.choices.is_empty() { button { onclick: move |_| { if let Some(state) = session.write().as_mut() { if let Err(e) = state.continue_dialogue() { state.message = e; } } }, "Continue" } } + } + } + p { role: "status", "{state.message}" } + } + } + } +} diff --git a/app/src/rehearsal.rs b/app/src/rehearsal.rs new file mode 100644 index 0000000..75b0c45 --- /dev/null +++ b/app/src/rehearsal.rs @@ -0,0 +1,120 @@ +//! An editor-only interaction rehearsal, not the unavailable PACE runtime. +//! It runs on an isolated snapshot and must never be used as game export. +use crate::model::{Action, Project}; +use std::collections::BTreeSet; + +#[derive(Clone)] +pub struct Rehearsal { + pub project: Project, + pub room_id: String, + pub inventory: BTreeSet, + pub dialogue_id: Option, + pub message: String, +} +impl Rehearsal { + pub fn new(project: &Project) -> Result { + let issues = project.validate(); + if !issues.is_empty() { + return Err(format!( + "Resolve {} validation error(s) before rehearsing.", + issues.len() + )); + } + Ok(Self { + project: project.clone(), + room_id: project.start_room.clone().ok_or("Choose a starting room")?, + inventory: BTreeSet::new(), + dialogue_id: None, + message: "Click a hotspot to try its action.".into(), + }) + } + pub fn activate(&mut self, hotspot_id: &str) -> Result<(), String> { + if self.dialogue_id.is_some() { + return Err("Finish the conversation first.".into()); + } + let h = self + .project + .room(&self.room_id) + .and_then(|r| r.hotspots.iter().find(|h| h.id == hotspot_id)) + .ok_or("Hotspot is not in the current room")? + .clone(); + if let Some(id) = &h.requires_item { + if !self.inventory.contains(id) { + let name = self + .project + .items + .iter() + .find(|i| &i.id == id) + .map(|i| i.name.as_str()) + .unwrap_or(id); + self.message = format!("You need {name} first."); + return Ok(()); + } + } + match h.action { + Action::Look { text } => self.message = text, + Action::GoTo { room_id } => { + if self.project.room(&room_id).is_none() { + return Err("Destination room is missing".into()); + } + self.room_id = room_id; + self.message = "You enter another room.".into(); + } + Action::Take { item_id } => { + let item = self + .project + .items + .iter() + .find(|i| i.id == item_id) + .ok_or("Item is missing")?; + self.message = if self.inventory.insert(item_id) { + format!("Picked up {}. {}", item.name, item.description) + } else { + format!("You already have {}.", item.name) + }; + } + Action::Talk { dialogue_id } => { + if !self.project.dialogues.iter().any(|d| d.id == dialogue_id) { + return Err("Dialogue is missing".into()); + } + self.dialogue_id = Some(dialogue_id); + self.message.clear(); + } + } + Ok(()) + } + pub fn choose(&mut self, choice_id: &str) -> Result<(), String> { + let choice = self + .project + .dialogues + .iter() + .find(|d| Some(&d.id) == self.dialogue_id.as_ref()) + .and_then(|d| d.choices.iter().find(|c| c.id == choice_id)) + .ok_or("Choice is not in the active dialogue")? + .clone(); + if let Some(item_id) = choice.give_item { + self.inventory.insert(item_id); + } + self.dialogue_id = choice.next; + self.message = if self.dialogue_id.is_none() { + "The conversation ends.".into() + } else { + String::new() + }; + Ok(()) + } + pub fn continue_dialogue(&mut self) -> Result<(), String> { + let d = self + .project + .dialogues + .iter() + .find(|d| Some(&d.id) == self.dialogue_id.as_ref()) + .ok_or("No active conversation")?; + if !d.choices.is_empty() { + return Err("Choose a response first".into()); + } + self.dialogue_id = None; + self.message = "The conversation ends.".into(); + Ok(()) + } +} diff --git a/app/src/rooms.rs b/app/src/rooms.rs index a46d062..43e2c21 100644 --- a/app/src/rooms.rs +++ b/app/src/rooms.rs @@ -90,6 +90,7 @@ pub fn RoomWorkspace(mut editor: Signal, mut notice: Signal) -> .map(|b| format!("{} × {}", b.width, b.height)) .unwrap_or_default(); rsx! { + div { class: "room-workspace", onkeydown: move |event| { if event.key() == Key::Escape { drag.set(None); drawing.set(false); } }, div { class: "room-heading", div { h1 { "{room.name}" } p { "Set the scene. Give every detail a story." } } label { class: "button", "Import background" input { r#type: "file", accept: "image/png,image/jpeg,image/webp", "aria-label": "Import background", onchange: move |event: Event| async move { @@ -119,7 +120,7 @@ pub fn RoomWorkspace(mut editor: Signal, mut notice: Signal) -> if let Some(room_id) = room_id { let mut id = None; editor.write().edit(|p| id = p.add_hotspot(&room_id, Rect { x:0.35,y:0.35,width:0.2,height:0.2 })); if let Some(id) = id { editor.write().selection = Selection::Hotspot(room_id,id); } } }, "Add hotspot" } } - div { id: "room-stage", class: if drawing() { "stage drawing" } else { "stage" }, style: "aspect-ratio:{background.width}/{background.height}", "aria-label": "Room canvas", + div { id: "room-stage", tabindex: "0", class: if drawing() { "stage drawing" } else { "stage" }, style: "aspect-ratio:{background.width}/{background.height}", "aria-label": "Room canvas", onkeydown: move |event| { if event.key() == Key::Escape { drag.set(None); drawing.set(false); } }, onpointerdown: move |event| { if drawing() && event.trigger_button() == Some(dioxus::html::input_data::MouseButton::Primary) { let point = event.client_coordinates(); if let Some(point) = browser::stage_point(point.x,point.y) { browser::capture_pointer(event.pointer_id()); drag.set(Some(Drag::Draw {start:point,end:point})); } @@ -136,7 +137,7 @@ pub fn RoomWorkspace(mut editor: Signal, mut notice: Signal) -> } } } } }, - img { src: "{background.data_url}", alt: "{room.name} background", draggable: "false" } + img { src: background.display_url(), alt: "{room.name} background", draggable: "false" } for hotspot in room.hotspots.clone() { HotspotButton { key: "{hotspot.id}", hotspot: hotspot.clone(), selected: selected_id.as_deref() == Some(&hotspot.id), editor, drag } } @@ -156,6 +157,7 @@ pub fn RoomWorkspace(mut editor: Signal, mut notice: Signal) -> } } } + } } } @@ -191,9 +193,7 @@ pub fn RoomInspector(mut editor: Signal) -> Element { .read() .selected_room() .and_then(|id| editor.read().project.room(id).cloned()); - let Some(room) = room else { - return rsx! {}; - }; + let room = room?; let hotspot = match &editor.read().selection { Selection::Hotspot(_, id) => room.hotspots.iter().find(|h| &h.id == id).cloned(), _ => None, @@ -215,15 +215,15 @@ pub fn RoomInspector(mut editor: Signal) -> Element { } } label { "Action" select { value: action, onchange: move |e| update_hotspot(editor, |h| h.action = match e.value().as_str() { "go_to" => Action::GoTo { room_id: String::new() }, "take" => Action::Take { item_id: String::new() }, "talk" => Action::Talk { dialogue_id: String::new() }, _ => Action::Look { text: String::new() } }), - option { value: "look", "Inspect" } option { value: "go_to", "Go to room" } option { value: "take", "Pick up item" } option { value: "talk", "Start dialogue" } + option { value: "look", selected: action == "look", "Inspect" } option { value: "go_to", selected: action == "go_to", "Go to room" } option { value: "take", selected: action == "take", "Pick up item" } option { value: "talk", selected: action == "talk", "Start dialogue" } } } match h.action { Action::Look {text} => rsx! { label { "Inspection text" textarea { value: "{text}", oninput: move |e| update_hotspot(editor, |h| h.action = Action::Look { text:e.value() }) } } }, - Action::GoTo {room_id} => rsx! { label { "Destination room" select { value: "{room_id}", onchange: move |e| update_hotspot(editor, |h| h.action = Action::GoTo { room_id:e.value() }), option { value: "", "Choose destination" } for r in editor.read().project.rooms.clone() { option { value: "{r.id}", "{r.name}" } } } } }, - Action::Take {item_id} => rsx! { label { "Item to pick up" select { value: "{item_id}", onchange: move |e| update_hotspot(editor, |h| h.action = Action::Take { item_id:e.value() }), option { value: "", "Choose item" } for item in editor.read().project.items.clone() { option { value: "{item.id}", "{item.name}" } } } } }, - Action::Talk {dialogue_id} => rsx! { label { "Dialogue to start" select { value: "{dialogue_id}", onchange: move |e| update_hotspot(editor, |h| h.action = Action::Talk { dialogue_id:e.value() }), option { value: "", "Choose dialogue" } for d in editor.read().project.dialogues.clone() { option { value: "{d.id}", "{d.name}" } } } } }, + Action::GoTo {room_id} => rsx! { label { "Destination room" select { value: "{room_id}", onchange: move |e| update_hotspot(editor, |h| h.action = Action::GoTo { room_id:e.value() }), option { value: "", selected: room_id.is_empty(), "Choose destination" } for r in editor.read().project.rooms.clone() { option { value: "{r.id}", selected: r.id == room_id, "{r.name}" } } } } }, + Action::Take {item_id} => rsx! { label { "Item to pick up" select { value: "{item_id}", onchange: move |e| update_hotspot(editor, |h| h.action = Action::Take { item_id:e.value() }), option { value: "", selected: item_id.is_empty(), "Choose item" } for item in editor.read().project.items.clone() { option { value: "{item.id}", selected: item.id == item_id, "{item.name}" } } } } }, + Action::Talk {dialogue_id} => rsx! { label { "Dialogue to start" select { value: "{dialogue_id}", onchange: move |e| update_hotspot(editor, |h| h.action = Action::Talk { dialogue_id:e.value() }), option { value: "", selected: dialogue_id.is_empty(), "Choose dialogue" } for d in editor.read().project.dialogues.clone() { option { value: "{d.id}", selected: d.id == dialogue_id, "{d.name}" } } } } }, } - label { "Requires item" select { value: h.requires_item.clone().unwrap_or_default(), onchange: move |e| update_hotspot(editor, |h| h.requires_item = if e.value().is_empty() { None } else { Some(e.value()) }), option { value: "", "No requirement" } for item in editor.read().project.items.clone() { option { value: "{item.id}", "{item.name}" } } } } + label { "Requires item" select { value: h.requires_item.clone().unwrap_or_default(), onchange: move |e| update_hotspot(editor, |h| h.requires_item = if e.value().is_empty() { None } else { Some(e.value()) }), option { value: "", selected: h.requires_item.is_none(), "No requirement" } for item in editor.read().project.items.clone() { option { value: "{item.id}", selected: h.requires_item.as_deref() == Some(item.id.as_str()), "{item.name}" } } } } p { class: "muted", "Room links are one-way. Add a return hotspot in the destination room." } button { class: "danger", onclick: move |_| editor.write().delete_selection(), "Delete hotspot" } } diff --git a/app/src/story.rs b/app/src/story.rs new file mode 100644 index 0000000..272b02b --- /dev/null +++ b/app/src/story.rs @@ -0,0 +1,102 @@ +use crate::{ + browser, + editor::{Editor, Selection}, + model::{Choice, Dialogue, Item}, +}; +use dioxus::prelude::*; + +fn update_item(mut editor: Signal, change: impl FnOnce(&mut Item)) { + let selection = editor.read().selection.clone(); + if let Selection::Item(id) = selection { + editor.write().edit(|p| { + if let Some(item) = p.items.iter_mut().find(|i| i.id == id) { + change(item); + } + }); + } +} +fn update_dialogue(mut editor: Signal, change: impl FnOnce(&mut Dialogue)) { + let selection = editor.read().selection.clone(); + if let Selection::Dialogue(id) = selection { + editor.write().edit(|p| { + if let Some(dialogue) = p.dialogues.iter_mut().find(|d| d.id == id) { + change(dialogue); + } + }); + } +} + +#[component] +pub fn StoryWorkspace(mut editor: Signal) -> Element { + let selection = editor.read().selection.clone(); + match selection { + Selection::Item(id) => { + let item = editor + .read() + .project + .items + .iter() + .find(|i| i.id == id) + .cloned(); + let item = item?; + rsx! { div { class: "room-heading", div { h1 { "{item.name}" } p { "Something to find. Something to take along." } } } + div { class: "card", h2 { "Inventory item" } p { class: "muted", "{item.id}" } + label { "Item name" input { value: "{item.name}", oninput: move |e| update_item(editor, |i| i.name = e.value()) } } + label { "Item description" textarea { value: "{item.description}", oninput: move |e| update_item(editor, |i| i.description = e.value()) } } + p { "Use a Pick up item hotspot or a dialogue reward to add this item to the player's inventory. A hotspot can require it before its action is available." } + button { class: "danger", onclick: move |_| { if browser::confirm("Delete this item? References will appear in validation. You can undo this.") { editor.write().delete_selection(); } }, "Delete item" } + } + } + } + Selection::Dialogue(id) => { + let dialogue = editor + .read() + .project + .dialogues + .iter() + .find(|d| d.id == id) + .cloned(); + let d = dialogue?; + rsx! { div { class: "room-heading", div { h1 { "{d.name}" } p { "A conversation can open a whole new world." } } } + div { class: "card", h2 { "Dialogue node" } p { class: "muted", "{d.id}" } + label { "Dialogue name" input { value: "{d.name}", oninput: move |e| update_dialogue(editor, |d| d.name = e.value()) } } + label { "Speaker" input { value: "{d.speaker}", oninput: move |e| update_dialogue(editor, |d| d.speaker = e.value()) } } + label { "Dialogue text" textarea { value: "{d.text}", oninput: move |e| update_dialogue(editor, |d| d.text = e.value()) } } + h3 { "PLAYER CHOICES" } + p { class: "muted", "Each choice can lead to another node and grant an item. No choices gives the player a Continue button to end the conversation." } + for choice in d.choices { ChoiceEditor { key: "{choice.id}", choice, editor } } + button { onclick: move |_| { + let selection = editor.read().selection.clone(); + if let Selection::Dialogue(dialogue_id) = selection { editor.write().edit(|p| { + let id = p.allocate_id("choice"); + if let Some(d) = p.dialogues.iter_mut().find(|d| d.id == dialogue_id) { d.choices.push(Choice { id, text: "New choice".into(), next: None, give_item: None }); } + }); } + }, "Add choice" } + br {} + button { class: "danger", onclick: move |_| { if browser::confirm("Delete this dialogue? References will appear in validation. You can undo this.") { editor.write().delete_selection(); } }, "Delete dialogue" } + } + } + } + _ => rsx! {}, + } +} + +#[component] +fn ChoiceEditor(choice: Choice, editor: Signal) -> Element { + let id = choice.id.clone(); + let next_id = id.clone(); + let item_id = id.clone(); + let delete_id = id.clone(); + rsx! { div { class: "choice", "data-choice-id": "{choice.id}", + label { "Choice text" input { value: "{choice.text}", oninput: move |e| update_dialogue(editor, |d| { if let Some(c) = d.choices.iter_mut().find(|c| c.id == id) { c.text = e.value(); } }) } } + label { "Next dialogue" select { value: choice.next.clone().unwrap_or_default(), onchange: move |e| update_dialogue(editor, |d| { if let Some(c) = d.choices.iter_mut().find(|c| c.id == next_id) { c.next = if e.value().is_empty() { None } else { Some(e.value()) }; } }), + option { value: "", selected: choice.next.is_none(), "End conversation" } + for dialogue in editor.read().project.dialogues.clone() { option { value: "{dialogue.id}", selected: choice.next.as_deref() == Some(dialogue.id.as_str()), "{dialogue.name}" } } + } } + label { "Give item" select { value: choice.give_item.clone().unwrap_or_default(), onchange: move |e| update_dialogue(editor, |d| { if let Some(c) = d.choices.iter_mut().find(|c| c.id == item_id) { c.give_item = if e.value().is_empty() { None } else { Some(e.value()) }; } }), + option { value: "", selected: choice.give_item.is_none(), "No item" } + for item in editor.read().project.items.clone() { option { value: "{item.id}", selected: choice.give_item.as_deref() == Some(item.id.as_str()), "{item.name}" } } + } } + button { onclick: move |_| update_dialogue(editor, |d| d.choices.retain(|c| c.id != delete_id)), "Remove choice" } + } } +} diff --git a/app/src/ui.rs b/app/src/ui.rs index e5d4204..0fd8583 100644 --- a/app/src/ui.rs +++ b/app/src/ui.rs @@ -21,6 +21,8 @@ pub fn App() -> Element { }); use_effect(move || browser::set_dirty(editor.read().dirty)); let issues = editor.read().project.validate(); + let has_issues = !issues.is_empty(); + let mut session = use_signal(|| None::); rsx! { style { {include_str!("editor.css")} } div { class: "app", @@ -47,7 +49,13 @@ pub fn App() -> Element { } button { class: "primary", onclick: move |_| { let result = editor.read().project.to_json().and_then(|text| { browser::download(&text)?; Ok(text) }); - match result { Ok(text) => { editor.write().dirty = false; notice.set(match browser::recover(&text) { Ok(()) => "Project file downloaded and browser recovery saved.".into(), Err(e) => format!("Project file downloaded. {e}") }); }, Err(e) => notice.set(e) } + match result { + Ok(text) => match browser::recover(&text) { + Ok(()) => { editor.write().dirty = false; notice.set("Project download requested and browser recovery saved.".into()); }, + Err(e) => notice.set(format!("Project download requested. {e}")), + }, + Err(e) => notice.set(e), + } }, "Save project" } } div { class: "dependency-banner", "Draft format v1 · PACE core integration pending. Your project files include all imported images." } @@ -60,6 +68,18 @@ pub fn App() -> Element { for room in editor.read().project.rooms.clone() { button { class: if editor.read().selected_room() == Some(room.id.as_str()) { "tree-row active" } else { "tree-row" }, onclick: move |_| editor.write().selection = Selection::Room(room.id.clone()), "{room.name}" } } + div { class: "section-heading", h2 { "INVENTORY" } button { "aria-label": "Add item", onclick: move |_| { + let mut id = String::new(); editor.write().edit(|p| id = p.add_item()); editor.write().selection = Selection::Item(id); + }, "+" } } + for item in editor.read().project.items.clone() { + button { class: if editor.read().selection == Selection::Item(item.id.clone()) { "tree-row active" } else { "tree-row" }, onclick: move |_| editor.write().selection = Selection::Item(item.id.clone()), "{item.name}" } + } + div { class: "section-heading", h2 { "DIALOGUE" } button { "aria-label": "Add dialogue", onclick: move |_| { + let mut id = String::new(); editor.write().edit(|p| id = p.add_dialogue()); editor.write().selection = Selection::Dialogue(id); + }, "+" } } + for dialogue in editor.read().project.dialogues.clone() { + button { class: if editor.read().selection == Selection::Dialogue(dialogue.id.clone()) { "tree-row active" } else { "tree-row" }, onclick: move |_| editor.write().selection = Selection::Dialogue(dialogue.id.clone()), "{dialogue.name}" } + } div { class: "sidebar-foot", "Build a world, one room at a time." } } main { class: "main-panel", @@ -67,14 +87,21 @@ pub fn App() -> Element { span { class: "eyebrow", "YOUR ADVENTURE" } button { disabled: !editor.read().can_undo(), onclick: move |_| editor.write().undo(), "Undo" } button { disabled: !editor.read().can_redo(), onclick: move |_| editor.write().redo(), "Redo" } + button { disabled: has_issues, onclick: move |_| { + match crate::rehearsal::Rehearsal::new(&editor.read().project) { Ok(state) => session.set(Some(state)), Err(e) => notice.set(e) } + }, "Rehearse draft" } + button { disabled: true, title: "No PACE core runtime is available at the inspected revision.", "Core preview" } + button { disabled: true, title: "Game export requires a pinned PACE core runtime.", "Export game" } } + if matches!(editor.read().selection, Selection::Item(_) | Selection::Dialogue(_)) { crate::story::StoryWorkspace { editor } } else { crate::rooms::RoomWorkspace { key: "{editor.read().selected_room().unwrap_or_default()}", editor, notice } + } } aside { class: "inspector", if editor.read().selected_room().is_some() { crate::rooms::RoomInspector { editor } } else { h2 { "Project" } label { "Project title" input { value: "{editor.read().project.title}", oninput: move |e| editor.write().edit(|p| p.title = e.value()) } } - label { "Starting room" select { value: editor.read().project.start_room.clone().unwrap_or_default(), onchange: move |e| editor.write().edit(|p| p.start_room = if e.value().is_empty() { None } else { Some(e.value()) }), option { value: "", "Choose a room" } for room in editor.read().project.rooms.clone() { option { value: "{room.id}", "{room.name}" } } } } + label { "Starting room" select { value: editor.read().project.start_room.clone().unwrap_or_default(), onchange: move |e| editor.write().edit(|p| p.start_room = if e.value().is_empty() { None } else { Some(e.value()) }), option { value: "", selected: editor.read().project.start_room.is_none(), "Choose a room" } for room in editor.read().project.rooms.clone() { option { value: "{room.id}", selected: editor.read().project.start_room.as_deref() == Some(room.id.as_str()), "{room.name}" } } } } } h3 { "Validation · {issues.len()}" } if issues.is_empty() { p { class: "success", "Ready for draft authoring." } } @@ -84,6 +111,7 @@ pub fn App() -> Element { } } footer { role: "status", "{notice}" } + if session.read().is_some() { crate::preview::DraftPreview { session } } } } } diff --git a/app/tests/project.rs b/app/tests/project.rs index 73352ab..86ca37c 100644 --- a/app/tests/project.rs +++ b/app/tests/project.rs @@ -158,16 +158,13 @@ fn canvas_geometry_handles_reverse_drag_clamping_and_tiny_gestures() { } ); assert!(Rect::from_drag((0.5, 0.5), (0.5, 0.6)).is_none()); - assert!( - Rect { - x: f64::NAN, - y: 0., - width: 0.1, - height: 0.1 - } - .valid() - == false - ); + assert!(!Rect { + x: f64::NAN, + y: 0., + width: 0.1, + height: 0.1 + } + .valid()); let moved = Rect { x: 0.1, y: 0.2, @@ -204,3 +201,17 @@ fn room_and_hotspot_operations_preserve_links_across_rename_and_report_deletion( e.undo(); assert_eq!(e.project, p); } +#[test] +fn non_finite_bounds_cannot_silently_serialize_as_null() { + let mut p = project(); + p.rooms[0].hotspots[0].rect.x = f64::INFINITY; + assert!(p.to_json().unwrap_err().contains("non-finite")); +} +#[test] +fn renderer_does_not_load_external_or_active_background_urls() { + let mut bg = background(); + bg.data_url = "https://example.com/tracking.png".into(); + assert_eq!(bg.display_url(), ""); + bg.data_url = "data:image/svg+xml,".into(); + assert_eq!(bg.display_url(), ""); +} diff --git a/app/tests/rehearsal.rs b/app/tests/rehearsal.rs new file mode 100644 index 0000000..f1f34fe --- /dev/null +++ b/app/tests/rehearsal.rs @@ -0,0 +1,90 @@ +use app::{model::*, rehearsal::Rehearsal}; +fn sample() -> Project { + let mut p = Project::default(); + let a = p.add_room(); + let b = p.add_room(); + for r in &mut p.rooms { + r.background = Some( + Background::import( + "test.png".into(), + include_bytes!("../../fixtures/backgrounds/foyer.png"), + ) + .unwrap(), + ); + } + let item = p.add_item(); + p.items[0].name = "Brass key".into(); + let dialogue = p.add_dialogue(); + let choice = p.allocate_id("choice"); + p.dialogues[0].choices.push(Choice { + id: choice, + text: "Take the key".into(), + next: None, + give_item: Some(item.clone()), + }); + let rect = Rect { + x: 0.1, + y: 0.1, + width: 0.2, + height: 0.2, + }; + p.add_hotspot(&a, rect); + p.add_hotspot(&a, rect); + p.add_hotspot(&a, rect); + p.rooms[0].hotspots[0].action = Action::GoTo { room_id: b }; + p.rooms[0].hotspots[0].requires_item = Some(item.clone()); + p.rooms[0].hotspots[1].action = Action::Talk { + dialogue_id: dialogue, + }; + p.rooms[0].hotspots[2].action = Action::Take { item_id: item }; + p +} +#[test] +fn item_gate_dialogue_reward_and_room_transition_do_not_mutate_project() { + let p = sample(); + let original = p.clone(); + let mut s = Rehearsal::new(&p).unwrap(); + let door = &p.rooms[0].hotspots[0].id; + s.activate(door).unwrap(); + assert_eq!(s.room_id, p.rooms[0].id); + assert_eq!(s.message, "You need Brass key first."); + assert!(s.choose("not active").is_err()); + s.activate(&p.rooms[0].hotspots[1].id).unwrap(); + assert!(s.activate(door).is_err()); + assert!(s.continue_dialogue().is_err()); + s.choose(&p.dialogues[0].choices[0].id).unwrap(); + assert!(s.inventory.contains(&p.items[0].id)); + assert_eq!(s.dialogue_id, None); + s.activate(door).unwrap(); + assert_eq!(s.room_id, p.rooms[1].id); + assert!(s.activate(door).is_err()); + assert_eq!(p, original); + assert_eq!(s.project, original); + let reset = Rehearsal::new(&p).unwrap(); + assert!(reset.inventory.is_empty()); + assert_eq!(reset.room_id, p.rooms[0].id); +} +#[test] +fn pickup_is_idempotent_and_invalid_projects_cannot_start() { + let mut p = sample(); + let mut s = Rehearsal::new(&p).unwrap(); + let pickup = &p.rooms[0].hotspots[2].id; + s.activate(pickup).unwrap(); + s.activate(pickup).unwrap(); + assert_eq!(s.inventory.len(), 1); + assert!(s.message.starts_with("You already have")); + p.items.clear(); + assert!(Rehearsal::new(&p).is_err()); +} +#[test] +fn dialogue_branches_and_terminal_continue_are_explicit() { + let mut p = sample(); + let terminal = p.add_dialogue(); + p.dialogues[0].choices[0].next = Some(terminal.clone()); + let mut s = Rehearsal::new(&p).unwrap(); + s.activate(&p.rooms[0].hotspots[1].id).unwrap(); + s.choose(&p.dialogues[0].choices[0].id).unwrap(); + assert_eq!(s.dialogue_id, Some(terminal)); + s.continue_dialogue().unwrap(); + assert!(s.dialogue_id.is_none()); +} diff --git a/docs/images/01-room-editor.png b/docs/images/01-room-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..0ff144ca4bcdbb3323749f94787d480b3dda0773 GIT binary patch literal 123990 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 literal 0 HcmV?d00001 diff --git a/docs/images/03-draft-rehearsal.png b/docs/images/03-draft-rehearsal.png new file mode 100644 index 0000000000000000000000000000000000000000..cb4e35d476558106f942e13da5ad5ec0817f04a1 GIT binary patch literal 74961 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 { + test.setTimeout(90_000); + const errors: string[] = []; + page.on('pageerror', e => errors.push(e.message)); + page.on('dialog', d => d.accept()); + await page.goto('/'); + await page.getByLabel('Project title', { exact: true }).fill('The Garden Key'); + await room(page, 'Foyer', 'foyer'); + await room(page, 'Study', 'study'); + await room(page, 'Garden', 'garden'); + for (const [name, description] of [['Brass key', 'Opens the study door.'], ['Garden pass', 'A gift from the gardener.']]) { + await page.getByRole('button', { name: 'Add item', exact: true }).click(); + await page.getByLabel('Item name', { exact: true }).fill(name); + await page.getByLabel('Item description', { exact: true }).fill(description); + } + await page.getByRole('button', { name: 'Add dialogue', exact: true }).click(); + await page.getByLabel('Dialogue name', { exact: true }).fill('Farewell'); + await page.getByLabel('Speaker', { exact: true }).fill('Gardener'); + await page.getByLabel('Dialogue text', { exact: true }).fill('The garden is waiting for you.'); + await page.getByRole('button', { name: 'Add dialogue', exact: true }).click(); + await page.getByLabel('Dialogue name', { exact: true }).fill('Meet the gardener'); + await page.getByLabel('Speaker', { exact: true }).fill('Gardener'); + await page.getByLabel('Dialogue text', { exact: true }).fill('Would you like to visit the garden?'); + await page.getByRole('button', { name: 'Add choice', exact: true }).click(); + await page.getByLabel('Choice text', { exact: true }).fill('May I enter?'); + await page.getByRole('combobox', { name: 'Next dialogue', exact: true }).selectOption({ label: 'Farewell' }); + await page.getByRole('combobox', { name: 'Give item', exact: true }).selectOption({ label: 'Garden pass' }); + await page.getByRole('button', { name: 'Add choice', exact: true }).click(); + await page.getByLabel('Choice text', { exact: true }).nth(1).fill('Not yet.'); + await hotspot(page, 'Foyer', 'Brass key on table', [44, 60, 16, 15], 'take', 'Brass key'); + await hotspot(page, 'Foyer', 'Study door', [72, 20, 20, 48], 'go_to', 'Study'); + await page.getByRole('combobox', { name: 'Requires item', exact: true }).selectOption({ label: 'Brass key' }); + await hotspot(page, 'Study', 'Return to foyer', [8, 20, 18, 48], 'go_to', 'Foyer'); + await hotspot(page, 'Study', 'Talk to gardener', [40, 55, 24, 18], 'talk', 'Meet the gardener'); + await hotspot(page, 'Study', 'Garden gate', [72, 20, 20, 48], 'go_to', 'Garden'); + await page.getByRole('combobox', { name: 'Requires item', exact: true }).selectOption({ label: 'Garden pass' }); + await hotspot(page, 'Garden', 'Return to study', [8, 20, 18, 48], 'go_to', 'Study'); + await hotspot(page, 'Garden', 'Statue', [42, 40, 18, 30], 'look', 'The garden remembers every visitor.'); + await expect(page.getByText('Validation · 0', { exact: true })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Core preview', exact: true })).toBeDisabled(); + await expect(page.getByRole('button', { name: 'Export game', exact: true })).toBeDisabled(); + const downloadPromise = page.waitForEvent('download'); + await page.getByRole('button', { name: 'Save project', exact: true }).click(); + const download = await downloadPromise; + const file = testInfo.outputPath('three-rooms.pace-draft.json'); + await download.saveAs(file); + const saved = JSON.parse(await fs.readFile(file, 'utf8')); + expect(saved.rooms.map((r: any) => r.name)).toEqual(['Foyer', 'Study', 'Garden']); + expect(saved.rooms.flatMap((r: any) => r.hotspots)).toHaveLength(7); + expect(saved.items).toHaveLength(2); expect(saved.dialogues).toHaveLength(2); + await page.getByRole('button', { name: 'Foyer', exact: true }).click(); + await page.getByRole('button', { name: 'Select hotspot Study door', exact: true }).click(); + await page.screenshot({ path: testInfo.outputPath('01-room-editor.png'), fullPage: true }); + if (process.env.UPDATE_WALKTHROUGH) { + await fs.copyFile(file, 'fixtures/three-rooms.pace-draft.json'); + await page.screenshot({ path: 'docs/images/01-room-editor.png', fullPage: true }); + } + await page.getByRole('button', { name: 'Meet the gardener', exact: true }).click(); + await expect(page.getByRole('combobox', { name: 'Starting room', exact: true }).locator('option:checked')).toHaveText('Foyer'); + await expect(page.getByRole('combobox', { name: 'Next dialogue', exact: true }).first().locator('option:checked')).toHaveText('Farewell'); + await expect(page.getByRole('combobox', { name: 'Give item', exact: true }).first().locator('option:checked')).toHaveText('Garden pass'); + await page.screenshot({ path: testInfo.outputPath('02-dialogue-editor.png'), fullPage: true }); + if (process.env.UPDATE_WALKTHROUGH) await page.screenshot({ path: 'docs/images/02-dialogue-editor.png', fullPage: true }); + await page.getByRole('button', { name: 'Rehearse draft', exact: true }).click(); + const preview = page.getByRole('dialog', { name: 'Draft rehearsal' }); + await preview.getByRole('button', { name: 'Interact with Study door', exact: true }).click(); + await expect(preview.getByRole('status')).toHaveText('You need Brass key first.'); + await preview.getByRole('button', { name: 'Interact with Brass key on table', exact: true }).click(); + await preview.getByRole('button', { name: 'Interact with Study door', exact: true }).click(); + await expect(preview.getByRole('heading', { name: 'Study', exact: true })).toBeVisible(); + await preview.getByRole('button', { name: 'Interact with Garden gate', exact: true }).click(); + await expect(preview.getByRole('status')).toHaveText('You need Garden pass first.'); + await preview.getByRole('button', { name: 'Interact with Talk to gardener', exact: true }).click(); + await preview.getByRole('button', { name: 'Not yet.', exact: true }).click(); + await expect(preview.getByRole('status')).toHaveText('The conversation ends.'); + await preview.getByRole('button', { name: 'Interact with Talk to gardener', exact: true }).click(); + await preview.getByRole('button', { name: 'May I enter?', exact: true }).click(); + await expect(preview.getByText('The garden is waiting for you.', { exact: true })).toBeVisible(); + await preview.getByRole('button', { name: 'Continue', exact: true }).click(); + await preview.getByRole('button', { name: 'Interact with Garden gate', exact: true }).click(); + await expect(preview.getByRole('heading', { name: 'Garden', exact: true })).toBeVisible(); + await preview.getByRole('button', { name: 'Interact with Statue', exact: true }).click(); + await expect(preview.getByRole('status')).toHaveText('The garden remembers every visitor.'); + if (process.env.UPDATE_WALKTHROUGH) await page.screenshot({ path: 'docs/images/03-draft-rehearsal.png' }); + await preview.getByRole('button', { name: 'Interact with Return to study', exact: true }).click(); + await preview.getByRole('button', { name: 'Interact with Return to foyer', exact: true }).click(); + await preview.getByRole('button', { name: 'Restart', exact: true }).click(); + await expect(preview.getByText('Nothing collected yet', { exact: true })).toBeVisible(); + await preview.getByRole('button', { name: 'Close rehearsal', exact: true }).click(); + await expect(preview).toHaveCount(0); + await page.getByRole('button', { name: 'Rehearse draft', exact: true }).click(); + // The native modal keeps keyboard focus away from editing controls. + for (let i = 0; i < 7; i++) { + await page.keyboard.press('Tab'); + expect(await page.evaluate(() => document.activeElement === document.body || !!document.activeElement?.closest('#draft-rehearsal'))).toBe(true); + } + await page.keyboard.press('Escape'); + await expect(preview).toHaveCount(0); + // Rehearsal must not dirty or change the authored data. + const afterPromise = page.waitForEvent('download'); + await page.getByRole('button', { name: 'Save project', exact: true }).click(); + await (await afterPromise).saveAs(testInfo.outputPath('after-rehearsal.json')); + expect(JSON.parse(await fs.readFile(testInfo.outputPath('after-rehearsal.json'), 'utf8'))).toEqual(saved); + await page.getByRole('button', { name: 'New project', exact: true }).click(); + await page.getByLabel('Open project', { exact: true }).setInputFiles(file); + await expect(page.getByText('Validation · 0', { exact: true })).toBeVisible(); + const reopenedPromise = page.waitForEvent('download'); + await page.getByRole('button', { name: 'Save project', exact: true }).click(); + await (await reopenedPromise).saveAs(testInfo.outputPath('reopened.json')); + expect(JSON.parse(await fs.readFile(testInfo.outputPath('reopened.json'), 'utf8'))).toEqual(saved); + expect(errors).toEqual([]); +}); diff --git a/tests/e2e/recovery.spec.ts b/tests/e2e/recovery.spec.ts new file mode 100644 index 0000000..56c3e35 --- /dev/null +++ b/tests/e2e/recovery.spec.ts @@ -0,0 +1,29 @@ +import { test, expect } from '@playwright/test'; +import fs from 'node:fs/promises'; + +test('quota failure preserves edits and offers a portable file; malformed open is non-destructive', async ({ page }, testInfo) => { + page.on('dialog', d => d.accept()); + await page.addInitScript(() => { + Storage.prototype.setItem = () => { throw new DOMException('Quota exceeded', 'QuotaExceededError'); }; + }); + await page.goto('/'); + await page.getByLabel('Project title', { exact: true }).fill('Keep this draft'); + const downloadPromise = page.waitForEvent('download'); + await page.getByRole('button', { name: 'Save project', exact: true }).click(); + const file = testInfo.outputPath('quota-draft.json'); + await (await downloadPromise).saveAs(file); + expect(JSON.parse(await fs.readFile(file, 'utf8')).title).toBe('Keep this draft'); + await expect(page.getByRole('status')).toContainText('Browser recovery is full or unavailable'); + await expect(page.locator('.project-title')).toContainText('•'); + await page.getByLabel('Open project', { exact: true }).setInputFiles({ name: 'broken.json', mimeType: 'application/json', buffer: Buffer.from('{broken') }); + await expect(page.getByRole('status')).toContainText('Invalid project JSON'); + await expect(page.getByLabel('Project title', { exact: true })).toHaveValue('Keep this draft'); +}); + +test('cancelled destructive action retains the current draft', async ({ page }) => { + page.on('dialog', d => d.dismiss()); + await page.goto('/'); + await page.getByLabel('Project title', { exact: true }).fill('Unsaved story'); + await page.getByRole('button', { name: 'New project', exact: true }).click(); + await expect(page.getByLabel('Project title', { exact: true })).toHaveValue('Unsaved story'); +}); diff --git a/tests/e2e/rooms.spec.ts b/tests/e2e/rooms.spec.ts index afdcb17..e40749b 100644 --- a/tests/e2e/rooms.spec.ts +++ b/tests/e2e/rooms.spec.ts @@ -25,6 +25,22 @@ test('import, draw, move, link, validate, undo, save and reopen rooms', async ({ await expect(page.getByLabel('X (%)', { exact: true })).toHaveValue((drawnX + 1).toFixed(2)); await page.getByRole('button', { name: 'Undo', exact: true }).click(); await expect(page.getByLabel('X (%)', { exact: true })).toHaveValue(drawnX.toFixed(2)); + const hit = await page.getByRole('button', { name: 'Select hotspot Study door', exact: true }).boundingBox(); + if (!hit) throw new Error('Missing hotspot'); + await page.mouse.move(hit.x + hit.width / 2, hit.y + hit.height / 2); + await page.mouse.down(); + await page.mouse.move(hit.x + hit.width / 2 + canvas.width * .05, hit.y + hit.height / 2, { steps: 6 }); + await page.mouse.up(); + expect(Math.abs(Number(await page.getByLabel('X (%)', { exact: true }).inputValue()) - drawnX - 5)).toBeLessThan(.2); + await page.getByRole('button', { name: 'Undo', exact: true }).click(); + await expect(page.getByLabel('X (%)', { exact: true })).toHaveValue(drawnX.toFixed(2)); + await page.getByRole('button', { name: 'Draw hotspot', exact: true }).click(); + await page.mouse.move(canvas.x + canvas.width * .5, canvas.y + canvas.height * .5); + await page.mouse.down(); + await page.mouse.move(canvas.x + canvas.width * .8, canvas.y + canvas.height * .8); + await page.keyboard.press('Escape'); + await page.mouse.up(); + await expect(page.locator('#room-stage .hotspot')).toHaveCount(1); await page.getByRole('button', { name: 'Add room', exact: true }).click(); await page.getByLabel('Room name', { exact: true }).fill('Study'); await page.getByLabel('Import background', { exact: true }).setInputFiles('fixtures/backgrounds/study.png'); diff --git a/web_view/index.html b/web_view/index.html index 6a738a7..034e039 100644 --- a/web_view/index.html +++ b/web_view/index.html @@ -4,6 +4,7 @@ + PACE — Adventure editor