diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f4e43e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/site/target/ +/site/dist/ diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..5715dfe --- /dev/null +++ b/flake.lock @@ -0,0 +1,48 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1789286504, + "narHash": "sha256-eiEK7cKZORNEvX0GeF3RtNEF/JXhgf2RqSp3230q13E=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ef34387ddd751e1ab8857adf4676492d32eb24ec", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1789457514, + "narHash": "sha256-Aggle++fTyAifBy+QBPxjM+obO5iepKW/8MDxQtgGvI=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "89e99bf0778a8f2cd18c9360c3f19c1ee47fc739", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..fb637b6 --- /dev/null +++ b/flake.nix @@ -0,0 +1,54 @@ +{ + description = "English reading lessons with a Leptos site"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { nixpkgs, rust-overlay, ... }: + let + systems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + + forEachSystem = f: nixpkgs.lib.genAttrs systems f; + in + { + devShells = forEachSystem (system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ (import rust-overlay) ]; + }; + + rustToolchain = pkgs.rust-bin.stable.latest.default.override { + targets = [ "wasm32-unknown-unknown" ]; + }; + in + { + default = pkgs.mkShell { + packages = [ + rustToolchain + pkgs.trunk + pkgs.wasm-bindgen-cli + pkgs.binaryen + pkgs.pkg-config + pkgs.git + ]; + + RUST_SRC_PATH = "${rustToolchain}/lib/rustlib/src/rust/library"; + + shellHook = '' + echo "Leptos shell ready. Run: trunk serve --open" + ''; + }; + }); + }; +} diff --git a/site/Cargo.lock b/site/Cargo.lock new file mode 100644 index 0000000..970575b --- /dev/null +++ b/site/Cargo.lock @@ -0,0 +1,1785 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "any_spawner" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41058deaa38c9d9dd933d6d238d825227cffa668e2839b52879f6619c63eee3b" +dependencies = [ + "futures", + "thiserror 2.0.20", + "wasm-bindgen-futures", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "attribute-derive" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05832cdddc8f2650cc2cc187cc2e952b8c133a48eb055f35211f61ee81502d77" +dependencies = [ + "attribute-derive-macro", + "derive-where", + "manyhow", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "attribute-derive-macro" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a7cdbbd4bd005c5d3e2e9c885e6fa575db4f4a3572335b974d8db853b6beb61" +dependencies = [ + "collection_literals", + "interpolator", + "manyhow", + "proc-macro-utils", + "proc-macro2", + "quote", + "quote-use", + "syn 2.0.119", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "camino" +version = "1.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbad30e4b4c14a39e3cc8aed085a12a327257c316619c93581e017bc52be591" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "codee" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9dbbdc4b4d349732bc6690de10a9de952bd39ba6a065c586e26600b6b0b91f5" +dependencies = [ + "serde", + "serde_json", + "thiserror 2.0.20", +] + +[[package]] +name = "collection_literals" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2550f75b8cfac212855f6b1885455df8eaee8fe8e246b647d69146142e016084" + +[[package]] +name = "config" +version = "0.15.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b85f248a4de22d204ceabc6299d89d2c70fbd7f09fea53c06c852369652d8139" +dependencies = [ + "convert_case 0.6.0", + "pathdiff", + "serde_core", + "toml", + "winnow", +] + +[[package]] +name = "const_format" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" +dependencies = [ + "const_format_proc_macros", + "konst", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "const_str_slice_concat" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f67855af358fcb20fac58f9d714c94e2b228fe5694c1c9b4ead4a366343eda1b" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + +[[package]] +name = "dashmap" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "derive-where" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "drain_filter_polyfill" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" + +[[package]] +name = "either_of" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5060e0a4cbf26a87550792688ade88e6b8aec9208613631a7a363bda7bc2d4cd" +dependencies = [ + "paste", + "pin-project-lite", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi", +] + +[[package]] +name = "gloo-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror 1.0.69", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "guardian" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e2ac29387b1aa07a1e448f7bb4f35b500787971e965b02842b900afa5c8f6f" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "html-escape" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9356095b4b41197bba32173600e1582792cda618f65d12f68e2e77d273413c5" + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "hydration_context" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d35485b3dcbf7e044b8f28c73f04f13e7b509c2466fd10cb2a8a447e38f8a93a" +dependencies = [ + "futures", + "once_cell", + "or_poisoned", + "pin-project-lite", + "serde", + "throw_error", +] + +[[package]] +name = "iana-reading" +version = "0.1.0" +dependencies = [ + "leptos", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "icu_collections" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "interpolator" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + +[[package]] +name = "leptos" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b8731cb00f3f0894058155410b95c8955b17273181d2bc72600ab84edd24f1" +dependencies = [ + "any_spawner", + "cfg-if", + "either_of", + "futures", + "hydration_context", + "leptos_config", + "leptos_dom", + "leptos_hot_reload", + "leptos_macro", + "leptos_server", + "oco_ref", + "or_poisoned", + "paste", + "reactive_graph", + "rustc-hash", + "send_wrapper", + "serde", + "serde_qs", + "server_fn", + "slotmap", + "tachys", + "thiserror 2.0.20", + "throw_error", + "typed-builder", + "typed-builder-macro", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos_config" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bae3e0ead5a7a814c8340eef7cb8b6cba364125bd8174b15dc9fe1b3cab7e03" +dependencies = [ + "config", + "regex", + "serde", + "thiserror 2.0.20", + "typed-builder", +] + +[[package]] +name = "leptos_dom" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89d4eb263bd5a9e7c49f780f17063f15aca56fd638c90b9dfd5f4739152e87d" +dependencies = [ + "js-sys", + "or_poisoned", + "reactive_graph", + "send_wrapper", + "tachys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos_hot_reload" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e80219388501d99b246f43b6e7d08a28f327cdd34ba630a35654d917f3e1788e" +dependencies = [ + "anyhow", + "camino", + "indexmap", + "parking_lot", + "proc-macro2", + "quote", + "rstml", + "serde", + "syn 2.0.119", + "walkdir", +] + +[[package]] +name = "leptos_macro" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e621f8f5342b9bdc93bb263b839cee7405027a74560425a2dabea9de7952b1fd" +dependencies = [ + "attribute-derive", + "cfg-if", + "convert_case 0.7.1", + "html-escape", + "itertools", + "leptos_hot_reload", + "prettyplease", + "proc-macro-error2", + "proc-macro2", + "quote", + "rstml", + "server_fn_macro", + "syn 2.0.119", + "uuid", +] + +[[package]] +name = "leptos_server" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66985242812ec95e224fb48effe651ba02728beca92c461a9464c811a71aab11" +dependencies = [ + "any_spawner", + "base64", + "codee", + "futures", + "hydration_context", + "or_poisoned", + "reactive_graph", + "send_wrapper", + "serde", + "serde_json", + "server_fn", + "tachys", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "linear-map" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "manyhow" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" +dependencies = [ + "manyhow-macros", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "manyhow-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "next_tuple" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60993920e071b0c9b66f14e2b32740a4e27ffc82854dcd72035887f336a09a28" + +[[package]] +name = "oco_ref" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed0423ff9973dea4d6bd075934fdda86ebb8c05bdf9d6b0507067d4a1226371d" +dependencies = [ + "serde", + "thiserror 2.0.20", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "or_poisoned" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c04f5d74368e4d0dfe06c45c8627c81bd7c317d52762d118fb9b3076f6420fd" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro-utils" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "version_check", + "yansi", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "quote-use" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9619db1197b497a36178cfc736dc96b271fe918875fbf1344c436a7e93d0321e" +dependencies = [ + "quote", + "quote-use-macros", +] + +[[package]] +name = "quote-use-macros" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "reactive_graph" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a0ccddbc11a648bd09761801dac9e3f246ef7641130987d6120fced22515e6" +dependencies = [ + "any_spawner", + "async-lock", + "futures", + "guardian", + "hydration_context", + "or_poisoned", + "pin-project-lite", + "rustc-hash", + "send_wrapper", + "serde", + "slotmap", + "thiserror 2.0.20", + "web-sys", +] + +[[package]] +name = "reactive_stores" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aadc7c19e3a360bf19cd595d2dc8b58ce67b9240b95a103fbc1317a8ff194237" +dependencies = [ + "guardian", + "itertools", + "or_poisoned", + "paste", + "reactive_graph", + "reactive_stores_macro", + "rustc-hash", +] + +[[package]] +name = "reactive_stores_macro" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "221095cb028dc51fbc2833743ea8b1a585da1a2af19b440b3528027495bf1f2d" +dependencies = [ + "convert_case 0.7.1", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rstml" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61cf4616de7499fc5164570d40ca4e1b24d231c6833a88bff0fe00725080fd56" +dependencies = [ + "derive-where", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.119", + "syn_derive", + "thiserror 2.0.20", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "same-file" +version = "1.0.6" +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 = "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.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_qs" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd34f36fe4c5ba9654417139a9b3a20d2e1de6012ee678ad14d240c22c78d8d6" +dependencies = [ + "percent-encoding", + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "server_fn" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d05a9e3fd8d7404985418db38c6617cc793a1a27f398d4fbc9dfe8e41b804e6" +dependencies = [ + "bytes", + "const_format", + "dashmap", + "futures", + "gloo-net", + "http", + "js-sys", + "once_cell", + "pin-project-lite", + "send_wrapper", + "serde", + "serde_json", + "serde_qs", + "server_fn_macro_default", + "thiserror 2.0.20", + "throw_error", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "xxhash-rust", +] + +[[package]] +name = "server_fn_macro" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504b35e883267b3206317b46d02952ed7b8bf0e11b2e209e2eb453b609a5e052" +dependencies = [ + "const_format", + "convert_case 0.6.0", + "proc-macro2", + "quote", + "syn 2.0.119", + "xxhash-rust", +] + +[[package]] +name = "server_fn_macro_default" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb8b274f568c94226a8045668554aace8142a59b8bca5414ac5a79627c825568" +dependencies = [ + "server_fn_macro", + "syn 2.0.119", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb066a04799e45f5d582e8fc6ec8e6d6896040d00898eb4e6a835196815b219" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tachys" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f66c3b70c32844a6f1e2943c72a33ebb777ad6acbeb20d1329d62e3a7806d6ec" +dependencies = [ + "any_spawner", + "async-trait", + "const_str_slice_concat", + "drain_filter_polyfill", + "dyn-clone", + "either_of", + "futures", + "html-escape", + "indexmap", + "itertools", + "js-sys", + "linear-map", + "next_tuple", + "oco_ref", + "once_cell", + "or_poisoned", + "parking_lot", + "paste", + "reactive_graph", + "reactive_stores", + "rustc-hash", + "send_wrapper", + "slotmap", + "throw_error", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl 2.0.20", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "throw_error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ef8bf264c6ae02a065a4a16553283f0656bd6266fc1fcb09fd2e6b5e91427b" +dependencies = [ + "pin-project-lite", +] + +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "1.1.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a" +dependencies = [ + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow", +] + +[[package]] +name = "typed-builder" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9d30e3a08026c78f246b173243cf07b3696d274debd26680773b6773c2afc7" +dependencies = [ + "typed-builder-macro", +] + +[[package]] +name = "typed-builder-macro" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c36781cc0e46a83726d9879608e4cf6c2505237e263a8eb8c24502989cfdb28" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[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.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef6dac1e96601b4fb3acccccff2139741fcb757cb9a36089bf5be91cfb285ce" +dependencies = [ + "getrandom", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[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 = "wasm-bindgen" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef4c5d3d2cdf5c54f4231181768f5510842e350db025faf1f7163b1030ed928" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.5", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbddc4a036f00ec4f18c83445bd3115cb306a91da554919a099d9222fe4a7f8" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "xxhash-rust" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aee1b19627c7c60102ab80d3a9cbe18de90bfe03bfa6c3715447681f0e8c8af6" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/site/Cargo.toml b/site/Cargo.toml new file mode 100644 index 0000000..d1608da --- /dev/null +++ b/site/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "iana-reading" +version = "0.1.0" +edition = "2021" + +[dependencies] +leptos = { version = "0.7", features = ["csr"] } +web-sys = { version = "0.3", features = ["HtmlAudioElement", "HtmlInputElement"] } +wasm-bindgen-futures = "0.4" diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..18f8219 --- /dev/null +++ b/site/index.html @@ -0,0 +1,14 @@ + + + + + + + + + Читаем по правилам — 01 + + + + + diff --git a/site/public/audio/.gitkeep b/site/public/audio/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/site/public/audio/and.mp3 b/site/public/audio/and.mp3 new file mode 100644 index 0000000..46626a4 Binary files /dev/null and b/site/public/audio/and.mp3 differ diff --git a/site/public/audio/at.mp3 b/site/public/audio/at.mp3 new file mode 100644 index 0000000..01f4ed4 Binary files /dev/null and b/site/public/audio/at.mp3 differ diff --git a/site/public/audio/bag.mp3 b/site/public/audio/bag.mp3 new file mode 100644 index 0000000..107d4dc Binary files /dev/null and b/site/public/audio/bag.mp3 differ diff --git a/site/public/audio/bags.mp3 b/site/public/audio/bags.mp3 new file mode 100644 index 0000000..32c85cf Binary files /dev/null and b/site/public/audio/bags.mp3 differ diff --git a/site/public/audio/ben.mp3 b/site/public/audio/ben.mp3 new file mode 100644 index 0000000..37ef84c Binary files /dev/null and b/site/public/audio/ben.mp3 differ diff --git a/site/public/audio/big.mp3 b/site/public/audio/big.mp3 new file mode 100644 index 0000000..4d8dd0b Binary files /dev/null and b/site/public/audio/big.mp3 differ diff --git a/site/public/audio/bike.mp3 b/site/public/audio/bike.mp3 new file mode 100644 index 0000000..85cb006 Binary files /dev/null and b/site/public/audio/bike.mp3 differ diff --git a/site/public/audio/bikes.mp3 b/site/public/audio/bikes.mp3 new file mode 100644 index 0000000..755d4e9 Binary files /dev/null and b/site/public/audio/bikes.mp3 differ diff --git a/site/public/audio/black.mp3 b/site/public/audio/black.mp3 new file mode 100644 index 0000000..74fcd46 Binary files /dev/null and b/site/public/audio/black.mp3 differ diff --git a/site/public/audio/bright.mp3 b/site/public/audio/bright.mp3 new file mode 100644 index 0000000..acb8884 Binary files /dev/null and b/site/public/audio/bright.mp3 differ diff --git a/site/public/audio/but.mp3 b/site/public/audio/but.mp3 new file mode 100644 index 0000000..ad6f8ce Binary files /dev/null and b/site/public/audio/but.mp3 differ diff --git a/site/public/audio/by.mp3 b/site/public/audio/by.mp3 new file mode 100644 index 0000000..1fbcc55 Binary files /dev/null and b/site/public/audio/by.mp3 differ diff --git a/site/public/audio/camp.mp3 b/site/public/audio/camp.mp3 new file mode 100644 index 0000000..e5f9aa9 Binary files /dev/null and b/site/public/audio/camp.mp3 differ diff --git a/site/public/audio/can.mp3 b/site/public/audio/can.mp3 new file mode 100644 index 0000000..3529a94 Binary files /dev/null and b/site/public/audio/can.mp3 differ diff --git a/site/public/audio/chat.mp3 b/site/public/audio/chat.mp3 new file mode 100644 index 0000000..7eb91ae Binary files /dev/null and b/site/public/audio/chat.mp3 differ diff --git a/site/public/audio/chip.mp3 b/site/public/audio/chip.mp3 new file mode 100644 index 0000000..f97ccc1 Binary files /dev/null and b/site/public/audio/chip.mp3 differ diff --git a/site/public/audio/chips.mp3 b/site/public/audio/chips.mp3 new file mode 100644 index 0000000..1d06fb0 Binary files /dev/null and b/site/public/audio/chips.mp3 differ diff --git a/site/public/audio/chop.mp3 b/site/public/audio/chop.mp3 new file mode 100644 index 0000000..752c667 Binary files /dev/null and b/site/public/audio/chop.mp3 differ diff --git a/site/public/audio/coins.mp3 b/site/public/audio/coins.mp3 new file mode 100644 index 0000000..d4aa907 Binary files /dev/null and b/site/public/audio/coins.mp3 differ diff --git a/site/public/audio/day.mp3 b/site/public/audio/day.mp3 new file mode 100644 index 0000000..4c8d08f Binary files /dev/null and b/site/public/audio/day.mp3 differ diff --git a/site/public/audio/dims.mp3 b/site/public/audio/dims.mp3 new file mode 100644 index 0000000..35e5ab4 Binary files /dev/null and b/site/public/audio/dims.mp3 differ diff --git a/site/public/audio/dish.mp3 b/site/public/audio/dish.mp3 new file mode 100644 index 0000000..7cb8033 Binary files /dev/null and b/site/public/audio/dish.mp3 differ diff --git a/site/public/audio/drip.mp3 b/site/public/audio/drip.mp3 new file mode 100644 index 0000000..9d16ef6 Binary files /dev/null and b/site/public/audio/drip.mp3 differ diff --git a/site/public/audio/dry.mp3 b/site/public/audio/dry.mp3 new file mode 100644 index 0000000..a0e1af9 Binary files /dev/null and b/site/public/audio/dry.mp3 differ diff --git a/site/public/audio/dusk.mp3 b/site/public/audio/dusk.mp3 new file mode 100644 index 0000000..9f8e36a Binary files /dev/null and b/site/public/audio/dusk.mp3 differ diff --git a/site/public/audio/end.mp3 b/site/public/audio/end.mp3 new file mode 100644 index 0000000..9c03ff1 Binary files /dev/null and b/site/public/audio/end.mp3 differ diff --git a/site/public/audio/ends.mp3 b/site/public/audio/ends.mp3 new file mode 100644 index 0000000..370b706 Binary files /dev/null and b/site/public/audio/ends.mp3 differ diff --git a/site/public/audio/fast.mp3 b/site/public/audio/fast.mp3 new file mode 100644 index 0000000..2fc78ac Binary files /dev/null and b/site/public/audio/fast.mp3 differ diff --git a/site/public/audio/fills.mp3 b/site/public/audio/fills.mp3 new file mode 100644 index 0000000..52cf868 Binary files /dev/null and b/site/public/audio/fills.mp3 differ diff --git a/site/public/audio/fish.mp3 b/site/public/audio/fish.mp3 new file mode 100644 index 0000000..84851bd Binary files /dev/null and b/site/public/audio/fish.mp3 differ diff --git a/site/public/audio/fix.mp3 b/site/public/audio/fix.mp3 new file mode 100644 index 0000000..1c3e43b Binary files /dev/null and b/site/public/audio/fix.mp3 differ diff --git a/site/public/audio/fresh.mp3 b/site/public/audio/fresh.mp3 new file mode 100644 index 0000000..b2b0488 Binary files /dev/null and b/site/public/audio/fresh.mp3 differ diff --git a/site/public/audio/grab.mp3 b/site/public/audio/grab.mp3 new file mode 100644 index 0000000..3aafff2 Binary files /dev/null and b/site/public/audio/grab.mp3 differ diff --git a/site/public/audio/grass.mp3 b/site/public/audio/grass.mp3 new file mode 100644 index 0000000..27c11da Binary files /dev/null and b/site/public/audio/grass.mp3 differ diff --git a/site/public/audio/grin.mp3 b/site/public/audio/grin.mp3 new file mode 100644 index 0000000..b340cd7 Binary files /dev/null and b/site/public/audio/grin.mp3 differ diff --git a/site/public/audio/gus.mp3 b/site/public/audio/gus.mp3 new file mode 100644 index 0000000..a22549a Binary files /dev/null and b/site/public/audio/gus.mp3 differ diff --git a/site/public/audio/has.mp3 b/site/public/audio/has.mp3 new file mode 100644 index 0000000..14cde40 Binary files /dev/null and b/site/public/audio/has.mp3 differ diff --git a/site/public/audio/help.mp3 b/site/public/audio/help.mp3 new file mode 100644 index 0000000..e4ba85e Binary files /dev/null and b/site/public/audio/help.mp3 differ diff --git a/site/public/audio/hike.mp3 b/site/public/audio/hike.mp3 new file mode 100644 index 0000000..ce99194 Binary files /dev/null and b/site/public/audio/hike.mp3 differ diff --git a/site/public/audio/hills.mp3 b/site/public/audio/hills.mp3 new file mode 100644 index 0000000..b9b5728 Binary files /dev/null and b/site/public/audio/hills.mp3 differ diff --git a/site/public/audio/his.mp3 b/site/public/audio/his.mp3 new file mode 100644 index 0000000..864766b Binary files /dev/null and b/site/public/audio/his.mp3 differ diff --git a/site/public/audio/hit.mp3 b/site/public/audio/hit.mp3 new file mode 100644 index 0000000..6be187b Binary files /dev/null and b/site/public/audio/hit.mp3 differ diff --git a/site/public/audio/hits.mp3 b/site/public/audio/hits.mp3 new file mode 100644 index 0000000..bd8044c Binary files /dev/null and b/site/public/audio/hits.mp3 differ diff --git a/site/public/audio/home.mp3 b/site/public/audio/home.mp3 new file mode 100644 index 0000000..6b37582 Binary files /dev/null and b/site/public/audio/home.mp3 differ diff --git a/site/public/audio/hot.mp3 b/site/public/audio/hot.mp3 new file mode 100644 index 0000000..fca4c3f Binary files /dev/null and b/site/public/audio/hot.mp3 differ diff --git a/site/public/audio/in.mp3 b/site/public/audio/in.mp3 new file mode 100644 index 0000000..0d90371 Binary files /dev/null and b/site/public/audio/in.mp3 differ diff --git a/site/public/audio/keep.mp3 b/site/public/audio/keep.mp3 new file mode 100644 index 0000000..a5e441a Binary files /dev/null and b/site/public/audio/keep.mp3 differ diff --git a/site/public/audio/lamps.mp3 b/site/public/audio/lamps.mp3 new file mode 100644 index 0000000..3653d12 Binary files /dev/null and b/site/public/audio/lamps.mp3 differ diff --git a/site/public/audio/last.mp3 b/site/public/audio/last.mp3 new file mode 100644 index 0000000..7c7d23d Binary files /dev/null and b/site/public/audio/last.mp3 differ diff --git a/site/public/audio/light.mp3 b/site/public/audio/light.mp3 new file mode 100644 index 0000000..4dc14e5 Binary files /dev/null and b/site/public/audio/light.mp3 differ diff --git a/site/public/audio/lights.mp3 b/site/public/audio/lights.mp3 new file mode 100644 index 0000000..9632958 Binary files /dev/null and b/site/public/audio/lights.mp3 differ diff --git a/site/public/audio/make.mp3 b/site/public/audio/make.mp3 new file mode 100644 index 0000000..d35d772 Binary files /dev/null and b/site/public/audio/make.mp3 differ diff --git a/site/public/audio/map.mp3 b/site/public/audio/map.mp3 new file mode 100644 index 0000000..1dd7f8c Binary files /dev/null and b/site/public/audio/map.mp3 differ diff --git a/site/public/audio/maps.mp3 b/site/public/audio/maps.mp3 new file mode 100644 index 0000000..3faa23e Binary files /dev/null and b/site/public/audio/maps.mp3 differ diff --git a/site/public/audio/may.mp3 b/site/public/audio/may.mp3 new file mode 100644 index 0000000..917925e Binary files /dev/null and b/site/public/audio/may.mp3 differ diff --git a/site/public/audio/next.mp3 b/site/public/audio/next.mp3 new file mode 100644 index 0000000..0af81db Binary files /dev/null and b/site/public/audio/next.mp3 differ diff --git a/site/public/audio/night.mp3 b/site/public/audio/night.mp3 new file mode 100644 index 0000000..bf31b0e Binary files /dev/null and b/site/public/audio/night.mp3 differ diff --git a/site/public/audio/on.mp3 b/site/public/audio/on.mp3 new file mode 100644 index 0000000..250d002 Binary files /dev/null and b/site/public/audio/on.mp3 differ diff --git a/site/public/audio/pack.mp3 b/site/public/audio/pack.mp3 new file mode 100644 index 0000000..7d0f9f8 Binary files /dev/null and b/site/public/audio/pack.mp3 differ diff --git a/site/public/audio/past.mp3 b/site/public/audio/past.mp3 new file mode 100644 index 0000000..2b8cc0d Binary files /dev/null and b/site/public/audio/past.mp3 differ diff --git a/site/public/audio/pick.mp3 b/site/public/audio/pick.mp3 new file mode 100644 index 0000000..11e4c3b Binary files /dev/null and b/site/public/audio/pick.mp3 differ diff --git a/site/public/audio/plan.mp3 b/site/public/audio/plan.mp3 new file mode 100644 index 0000000..d4bdc9c Binary files /dev/null and b/site/public/audio/plan.mp3 differ diff --git a/site/public/audio/pond.mp3 b/site/public/audio/pond.mp3 new file mode 100644 index 0000000..a86d407 Binary files /dev/null and b/site/public/audio/pond.mp3 differ diff --git a/site/public/audio/rain.mp3 b/site/public/audio/rain.mp3 new file mode 100644 index 0000000..026cd83 Binary files /dev/null and b/site/public/audio/rain.mp3 differ diff --git a/site/public/audio/red.mp3 b/site/public/audio/red.mp3 new file mode 100644 index 0000000..de84e8c Binary files /dev/null and b/site/public/audio/red.mp3 differ diff --git a/site/public/audio/ride.mp3 b/site/public/audio/ride.mp3 new file mode 100644 index 0000000..204b6f4 Binary files /dev/null and b/site/public/audio/ride.mp3 differ diff --git a/site/public/audio/road.mp3 b/site/public/audio/road.mp3 new file mode 100644 index 0000000..a64925b Binary files /dev/null and b/site/public/audio/road.mp3 differ diff --git a/site/public/audio/rocks.mp3 b/site/public/audio/rocks.mp3 new file mode 100644 index 0000000..72eea27 Binary files /dev/null and b/site/public/audio/rocks.mp3 differ diff --git a/site/public/audio/runs.mp3 b/site/public/audio/runs.mp3 new file mode 100644 index 0000000..c45d187 Binary files /dev/null and b/site/public/audio/runs.mp3 differ diff --git a/site/public/audio/rush.mp3 b/site/public/audio/rush.mp3 new file mode 100644 index 0000000..19db482 Binary files /dev/null and b/site/public/audio/rush.mp3 differ diff --git a/site/public/audio/safe.mp3 b/site/public/audio/safe.mp3 new file mode 100644 index 0000000..910a78f Binary files /dev/null and b/site/public/audio/safe.mp3 differ diff --git a/site/public/audio/sam.mp3 b/site/public/audio/sam.mp3 new file mode 100644 index 0000000..a35cc51 Binary files /dev/null and b/site/public/audio/sam.mp3 differ diff --git a/site/public/audio/sand.mp3 b/site/public/audio/sand.mp3 new file mode 100644 index 0000000..f4505ba Binary files /dev/null and b/site/public/audio/sand.mp3 differ diff --git a/site/public/audio/see.mp3 b/site/public/audio/see.mp3 new file mode 100644 index 0000000..fa777f4 Binary files /dev/null and b/site/public/audio/see.mp3 differ diff --git a/site/public/audio/shells.mp3 b/site/public/audio/shells.mp3 new file mode 100644 index 0000000..a353e27 Binary files /dev/null and b/site/public/audio/shells.mp3 differ diff --git a/site/public/audio/shine.mp3 b/site/public/audio/shine.mp3 new file mode 100644 index 0000000..e931316 Binary files /dev/null and b/site/public/audio/shine.mp3 differ diff --git a/site/public/audio/sing.mp3 b/site/public/audio/sing.mp3 new file mode 100644 index 0000000..3b4e3e9 Binary files /dev/null and b/site/public/audio/sing.mp3 differ diff --git a/site/public/audio/sit.mp3 b/site/public/audio/sit.mp3 new file mode 100644 index 0000000..f033c87 Binary files /dev/null and b/site/public/audio/sit.mp3 differ diff --git a/site/public/audio/sits.mp3 b/site/public/audio/sits.mp3 new file mode 100644 index 0000000..d54f5fa Binary files /dev/null and b/site/public/audio/sits.mp3 differ diff --git a/site/public/audio/sky.mp3 b/site/public/audio/sky.mp3 new file mode 100644 index 0000000..a811665 Binary files /dev/null and b/site/public/audio/sky.mp3 differ diff --git a/site/public/audio/spot.mp3 b/site/public/audio/spot.mp3 new file mode 100644 index 0000000..6e7f1c1 Binary files /dev/null and b/site/public/audio/spot.mp3 differ diff --git a/site/public/audio/sticks.mp3 b/site/public/audio/sticks.mp3 new file mode 100644 index 0000000..47d6bd6 Binary files /dev/null and b/site/public/audio/sticks.mp3 differ diff --git a/site/public/audio/stops.mp3 b/site/public/audio/stops.mp3 new file mode 100644 index 0000000..1f7384e Binary files /dev/null and b/site/public/audio/stops.mp3 differ diff --git a/site/public/audio/sun.mp3 b/site/public/audio/sun.mp3 new file mode 100644 index 0000000..c4ddd60 Binary files /dev/null and b/site/public/audio/sun.mp3 differ diff --git a/site/public/audio/swim.mp3 b/site/public/audio/swim.mp3 new file mode 100644 index 0000000..fe8295d Binary files /dev/null and b/site/public/audio/swim.mp3 differ diff --git a/site/public/audio/tape.mp3 b/site/public/audio/tape.mp3 new file mode 100644 index 0000000..eaf7c5c Binary files /dev/null and b/site/public/audio/tape.mp3 differ diff --git a/site/public/audio/tent.mp3 b/site/public/audio/tent.mp3 new file mode 100644 index 0000000..57c0d0f Binary files /dev/null and b/site/public/audio/tent.mp3 differ diff --git a/site/public/audio/tents.mp3 b/site/public/audio/tents.mp3 new file mode 100644 index 0000000..2f24940 Binary files /dev/null and b/site/public/audio/tents.mp3 differ diff --git a/site/public/audio/tim.mp3 b/site/public/audio/tim.mp3 new file mode 100644 index 0000000..f052687 Binary files /dev/null and b/site/public/audio/tim.mp3 differ diff --git a/site/public/audio/trails.mp3 b/site/public/audio/trails.mp3 new file mode 100644 index 0000000..64f3ac6 Binary files /dev/null and b/site/public/audio/trails.mp3 differ diff --git a/site/public/audio/trip.mp3 b/site/public/audio/trip.mp3 new file mode 100644 index 0000000..a1c2f8d Binary files /dev/null and b/site/public/audio/trip.mp3 differ diff --git a/site/public/audio/up.mp3 b/site/public/audio/up.mp3 new file mode 100644 index 0000000..a2dbe22 Binary files /dev/null and b/site/public/audio/up.mp3 differ diff --git a/site/public/audio/wait.mp3 b/site/public/audio/wait.mp3 new file mode 100644 index 0000000..06b78d8 Binary files /dev/null and b/site/public/audio/wait.mp3 differ diff --git a/site/public/audio/wash.mp3 b/site/public/audio/wash.mp3 new file mode 100644 index 0000000..3983418 Binary files /dev/null and b/site/public/audio/wash.mp3 differ diff --git a/site/public/audio/wave.mp3 b/site/public/audio/wave.mp3 new file mode 100644 index 0000000..540748c Binary files /dev/null and b/site/public/audio/wave.mp3 differ diff --git a/site/public/audio/wet.mp3 b/site/public/audio/wet.mp3 new file mode 100644 index 0000000..c821bd0 Binary files /dev/null and b/site/public/audio/wet.mp3 differ diff --git a/site/public/audio/wide.mp3 b/site/public/audio/wide.mp3 new file mode 100644 index 0000000..d3b9469 Binary files /dev/null and b/site/public/audio/wide.mp3 differ diff --git a/site/src/data.rs b/site/src/data.rs new file mode 100644 index 0000000..00d39a4 --- /dev/null +++ b/site/src/data.rs @@ -0,0 +1,831 @@ +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Word { + pub id: &'static str, + pub spelling: &'static str, + pub ipa_us: &'static str, + pub russian_hint: &'static str, + pub audio_path: &'static str, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Token { + Word { + word_id: &'static str, + surface: &'static str, + }, + Punctuation(&'static str), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct ReadingText { + pub id: &'static str, + pub title: &'static str, + pub tokens: &'static [Token], +} + +macro_rules! entry { + ($id:literal, $ipa:literal, $hint:literal) => { + Word { + id: $id, + spelling: $id, + ipa_us: $ipa, + russian_hint: $hint, + audio_path: concat!("/audio/", $id, ".mp3"), + } + }; +} +macro_rules! word { + ($id:literal) => { + Token::Word { + word_id: $id, + surface: $id, + } + }; + ($id:literal, $surface:literal) => { + Token::Word { + word_id: $id, + surface: $surface, + } + }; +} +macro_rules! punct { + ($value:literal) => { + Token::Punctuation($value) + }; +} + +pub const DICTIONARY: &[Word] = &[ + entry!("sam", "sæm", "сэм"), + entry!("and", "ænd", "энд"), + entry!("ben", "bɛn", "бэн"), + entry!("sit", "sɪt", "сит"), + entry!("at", "æt", "эт"), + entry!("camp", "kæmp", "кэмп"), + entry!("plan", "plæn", "плэн"), + entry!("next", "nɛkst", "нэкст"), + entry!("trip", "trɪp", "трип"), + entry!("tim", "tɪm", "тим"), + entry!("gus", "ɡʌs", "гас"), + entry!("pack", "pæk", "пэк"), + entry!("red", "rɛd", "рэд"), + entry!("bags", "bæɡz", "бэгз"), + entry!("fresh", "frɛʃ", "фреш"), + entry!("fish", "fɪʃ", "фиш"), + entry!("chips", "tʃɪps", "чипс"), + entry!("has", "hæz", "хэз"), + entry!("his", "hɪz", "хиз"), + entry!("map", "mæp", "мэп"), + entry!("big", "bɪɡ", "биг"), + entry!("maps", "mæps", "мэпс"), + entry!("black", "blæk", "блэк"), + entry!("in", "ɪn", "ин"), + entry!("sits", "sɪts", "ситс"), + entry!("past", "pæst", "пэст"), + entry!("hills", "hɪlz", "хилз"), + entry!("wide", "waɪd", "уайд"), + entry!("grass", "ɡræs", "грэс"), + entry!("trails", "treɪlz", "трейлз"), + entry!("rain", "reɪn", "рейн"), + entry!("hits", "hɪts", "хитс"), + entry!("runs", "rʌnz", "ранз"), + entry!("rocks", "rɑks", "ракс"), + entry!("wait", "weɪt", "уэйт"), + entry!("tents", "tɛnts", "тентс"), + entry!("chat", "tʃæt", "чэт"), + entry!("can", "kæn", "кэн"), + entry!("see", "siː", "си"), + entry!("drip", "drɪp", "дрип"), + entry!("on", "ɑn", "ан"), + entry!("fast", "fæst", "фэст"), + entry!("swim", "swɪm", "свим"), + entry!("pond", "pɑnd", "панд"), + entry!("grab", "ɡræb", "грэб"), + entry!("rush", "rʌʃ", "раш"), + entry!("wet", "wɛt", "уэт"), + entry!("make", "meɪk", "мейк"), + entry!("bright", "braɪt", "брайт"), + entry!("light", "laɪt", "лайт"), + entry!("dry", "draɪ", "драй"), + entry!("sticks", "stɪks", "стикс"), + entry!("help", "hɛlp", "хэлп"), + entry!("chip", "tʃɪp", "чип"), + entry!("dish", "dɪʃ", "диш"), + entry!("ends", "ɛndz", "эндз"), + entry!("sun", "sʌn", "сан"), + entry!("shine", "ʃaɪn", "шайн"), + entry!("hike", "haɪk", "хайк"), + entry!("ride", "raɪd", "райд"), + entry!("bikes", "baɪks", "байкс"), + entry!("pick", "pɪk", "пик"), + entry!("coins", "kɔɪnz", "койнз"), + entry!("sand", "sænd", "сэнд"), + entry!("by", "baɪ", "бай"), + entry!("road", "roʊd", "роуд"), + entry!("shells", "ʃɛlz", "шелз"), + entry!("wash", "wɑʃ", "уош"), + entry!("chop", "tʃɑp", "чап"), + entry!("fix", "fɪks", "фикс"), + entry!("bike", "baɪk", "байк"), + entry!("tape", "teɪp", "тейп"), + entry!("night", "naɪt", "найт"), + entry!("fills", "fɪlz", "филз"), + entry!("sky", "skaɪ", "скай"), + entry!("dims", "dɪmz", "димз"), + entry!("sing", "sɪŋ", "синг"), + entry!("grin", "ɡrɪn", "грин"), + entry!("may", "meɪ", "мей"), + entry!("hit", "hɪt", "хит"), + entry!("but", "bʌt", "бат"), + entry!("lamps", "læmps", "лэмпс"), + entry!("keep", "kiːp", "кип"), + entry!("tent", "tɛnt", "тент"), + entry!("safe", "seɪf", "сейф"), + entry!("bag", "bæɡ", "бэг"), + entry!("day", "deɪ", "дей"), + entry!("stops", "stɑps", "стапс"), + entry!("spot", "spɑt", "спат"), + entry!("hot", "hɑt", "хат"), + entry!("last", "læst", "лэст"), + entry!("up", "ʌp", "ап"), + entry!("home", "hoʊm", "хоум"), + entry!("dusk", "dʌsk", "даск"), + entry!("end", "ɛnd", "энд"), + entry!("lights", "laɪts", "лайтс"), + entry!("wave", "weɪv", "уэйв"), +]; + +const BASIC_RULES_TOKENS: &[Token] = &[ + word!("sam", "Sam"), + word!("and"), + word!("ben", "Ben"), + word!("sit"), + word!("at"), + word!("camp"), + word!("and"), + word!("plan"), + word!("next"), + word!("trip"), + punct!("."), + word!("tim", "Tim"), + word!("and"), + word!("gus", "Gus"), + word!("pack"), + word!("red"), + word!("bags"), + word!("fresh"), + word!("fish"), + word!("and"), + word!("chips"), + punct!("."), + word!("sam", "Sam"), + word!("has"), + word!("his"), + word!("map"), + word!("and"), + word!("ben", "Ben"), + word!("has"), + word!("his"), + word!("big"), + word!("map"), + punct!("."), + word!("tim", "Tim"), + word!("has"), + word!("red"), + word!("maps"), + punct!(";"), + word!("gus", "Gus"), + word!("has"), + word!("black"), + word!("maps"), + word!("in"), + word!("camp"), + punct!("."), + word!("camp", "Camp"), + word!("sits"), + word!("past"), + word!("big"), + word!("hills"), + word!("and"), + word!("wide"), + word!("camp"), + word!("grass"), + word!("trails"), + punct!("."), + word!("rain", "Rain"), + word!("hits"), + word!("grass"), + word!("and"), + word!("runs"), + word!("past"), + word!("black"), + word!("rocks"), + word!("in"), + word!("camp"), + punct!("."), + word!("sam", "Sam"), + punct!(","), + word!("ben", "Ben"), + punct!(","), + word!("tim", "Tim"), + punct!(","), + word!("and"), + word!("gus", "Gus"), + word!("wait"), + word!("in"), + word!("tents"), + word!("and"), + word!("chat"), + punct!("."), + word!("gus", "Gus"), + word!("can"), + word!("see"), + word!("rain"), + word!("drip"), + word!("on"), + word!("red"), + word!("camp"), + word!("tents"), + word!("fast"), + punct!("."), + word!("ben", "Ben"), + word!("can"), + word!("see"), + word!("fish"), + word!("swim"), + word!("in"), + word!("big"), + word!("camp"), + word!("pond"), + word!("fast"), + punct!("."), + word!("tim", "Tim"), + word!("and"), + word!("gus", "Gus"), + word!("grab"), + word!("bags"), + word!("and"), + word!("rush"), + word!("past"), + word!("wet"), + word!("grass"), + punct!("."), + word!("sam", "Sam"), + word!("can"), + word!("make"), + word!("bright"), + word!("camp"), + word!("light"), + punct!(";"), + word!("dry"), + word!("sticks"), + word!("help"), + word!("sam", "Sam"), + punct!("."), + word!("ben", "Ben"), + word!("can"), + word!("make"), + word!("fresh"), + word!("fish"), + word!("chip"), + word!("dish"), + word!("at"), + word!("camp"), + word!("tent"), + punct!("."), + word!("rain", "Rain"), + word!("ends"), + word!("and"), + word!("sun"), + word!("can"), + word!("shine"), + word!("on"), + word!("hills"), + word!("at"), + word!("camp"), + punct!("."), + word!("sam", "Sam"), + word!("and"), + word!("ben", "Ben"), + word!("hike"), + word!("past"), + word!("big"), + word!("rocks"), + word!("in"), + word!("rain"), + word!("fast"), + punct!("."), + word!("tim", "Tim"), + word!("and"), + word!("gus", "Gus"), + word!("ride"), + word!("bikes"), + word!("on"), + word!("wide"), + word!("camp"), + word!("grass"), + word!("trails"), + punct!("."), + word!("sam", "Sam"), + word!("can"), + word!("pick"), + word!("coins"), + word!("in"), + word!("sand"), + word!("by"), + word!("wide"), + word!("camp"), + word!("road"), + punct!("."), + word!("ben", "Ben"), + word!("can"), + word!("pick"), + word!("bright"), + word!("shells"), + word!("in"), + word!("sand"), + word!("by"), + word!("wide"), + word!("road"), + punct!("."), + word!("tim", "Tim"), + word!("can"), + word!("wash"), + word!("fish"), + word!("and"), + word!("chop"), + word!("red"), + word!("chips"), + word!("at"), + word!("camp"), + punct!("."), + word!("gus", "Gus"), + word!("can"), + word!("fix"), + word!("his"), + word!("bike"), + punct!(";"), + word!("black"), + word!("tape"), + word!("can"), + word!("help"), + word!("gus", "Gus"), + punct!("."), + word!("sam", "Sam"), + word!("and"), + word!("ben", "Ben"), + word!("help"), + word!("gus", "Gus"), + word!("fix"), + word!("his"), + word!("bike"), + word!("at"), + word!("camp"), + punct!("."), + word!("night", "Night"), + word!("fills"), + word!("camp"), + word!("and"), + word!("black"), + word!("sky"), + word!("dims"), + word!("camp"), + word!("trails"), + word!("fast"), + punct!("."), + word!("sam", "Sam"), + word!("and"), + word!("ben", "Ben"), + word!("sit"), + word!("by"), + word!("bright"), + word!("camp"), + word!("light"), + word!("and"), + word!("sing"), + punct!("."), + word!("tim", "Tim"), + word!("and"), + word!("gus", "Gus"), + word!("sit"), + word!("by"), + word!("bright"), + word!("camp"), + word!("light"), + word!("and"), + word!("grin"), + punct!("."), + word!("rain", "Rain"), + word!("may"), + word!("hit"), + word!("tents"), + word!("but"), + word!("camp"), + word!("lamps"), + word!("make"), + word!("bright"), + word!("light"), + punct!("."), + word!("sam", "Sam"), + word!("can"), + word!("keep"), + word!("dry"), + word!("bags"), + word!("in"), + word!("his"), + word!("tent"), + word!("at"), + word!("camp"), + punct!("."), + word!("ben", "Ben"), + word!("can"), + word!("keep"), + word!("his"), + word!("map"), + word!("safe"), + word!("in"), + word!("tent"), + word!("at"), + word!("camp"), + punct!("."), + word!("tim", "Tim"), + word!("can"), + word!("keep"), + word!("fish"), + word!("fresh"), + word!("in"), + word!("his"), + word!("bag"), + word!("at"), + word!("camp"), + punct!("."), + word!("gus", "Gus"), + word!("can"), + word!("keep"), + word!("red"), + word!("chips"), + word!("in"), + word!("his"), + word!("bag"), + word!("at"), + word!("camp"), + punct!("."), + word!("day", "Day"), + word!("ends"), + punct!(";"), + word!("rain"), + word!("stops"), + punct!("."), + word!("sun", "Sun"), + word!("can"), + word!("shine"), + word!("at"), + word!("red"), + word!("camp"), + punct!("."), + word!("sam", "Sam"), + word!("and"), + word!("ben", "Ben"), + word!("plan"), + word!("next"), + word!("hike"), + word!("by"), + word!("wide"), + word!("camp"), + word!("road"), + punct!("."), + word!("tim", "Tim"), + word!("and"), + word!("gus", "Gus"), + word!("plan"), + word!("next"), + word!("bike"), + word!("ride"), + word!("by"), + word!("camp"), + word!("road"), + punct!("."), + word!("sam", "Sam"), + word!("can"), + word!("help"), + word!("ben", "Ben"), + word!("past"), + word!("rocks"), + word!("and"), + word!("wet"), + word!("camp"), + word!("grass"), + punct!("."), + word!("tim", "Tim"), + word!("can"), + word!("help"), + word!("gus", "Gus"), + word!("past"), + word!("hills"), + word!("and"), + word!("red"), + word!("camp"), + word!("tents"), + punct!("."), + word!("ben", "Ben"), + word!("can"), + word!("ride"), + word!("bike"), + word!("past"), + word!("camp"), + word!("pond"), + word!("and"), + word!("rocks"), + word!("fast"), + punct!("."), + word!("gus", "Gus"), + word!("can"), + word!("ride"), + word!("bike"), + word!("past"), + word!("wet"), + word!("grass"), + word!("and"), + word!("tents"), + word!("fast"), + punct!("."), + word!("sam", "Sam"), + word!("can"), + word!("see"), + word!("bright"), + word!("light"), + word!("on"), + word!("camp"), + word!("road"), + word!("at"), + word!("night"), + punct!("."), + word!("ben", "Ben"), + word!("can"), + word!("see"), + word!("bright"), + word!("lights"), + word!("at"), + word!("night"), + word!("in"), + word!("his"), + word!("camp"), + punct!("."), + word!("tim", "Tim"), + word!("can"), + word!("spot"), + word!("red"), + word!("fish"), + word!("in"), + word!("pond"), + word!("at"), + word!("night"), + word!("fast"), + punct!("."), + word!("gus", "Gus"), + word!("can"), + word!("spot"), + word!("big"), + word!("fish"), + word!("in"), + word!("pond"), + word!("at"), + word!("night"), + word!("fast"), + punct!("."), + word!("sam", "Sam"), + word!("and"), + word!("ben", "Ben"), + word!("make"), + word!("hot"), + word!("fish"), + word!("dish"), + word!("in"), + word!("camp"), + word!("tent"), + punct!("."), + word!("tim", "Tim"), + word!("and"), + word!("gus", "Gus"), + word!("make"), + word!("fresh"), + word!("chip"), + word!("dish"), + word!("in"), + word!("camp"), + word!("tent"), + punct!("."), + word!("rain", "Rain"), + word!("ends"), + word!("and"), + word!("camp"), + word!("trails"), + word!("dry"), + word!("in"), + word!("sun"), + word!("at"), + word!("last"), + punct!("."), + word!("sam", "Sam"), + word!("and"), + word!("ben", "Ben"), + word!("pick"), + word!("wet"), + word!("tents"), + word!("up"), + word!("and"), + word!("pack"), + word!("fast"), + punct!("."), + word!("tim", "Tim"), + word!("and"), + word!("gus", "Gus"), + word!("pack"), + word!("fish"), + word!("chips"), + word!("maps"), + word!("and"), + word!("bags"), + word!("fast"), + punct!("."), + word!("sam", "Sam"), + word!("and"), + word!("ben", "Ben"), + word!("hike"), + word!("home"), + word!("by"), + word!("wide"), + word!("road"), + word!("at"), + word!("dusk"), + punct!("."), + word!("tim", "Tim"), + word!("and"), + word!("gus", "Gus"), + word!("ride"), + word!("home"), + word!("by"), + word!("wide"), + word!("road"), + word!("at"), + word!("dusk"), + punct!("."), + word!("sam", "Sam"), + word!("can"), + word!("see"), + word!("rain"), + word!("end"), + word!("and"), + word!("sun"), + word!("shine"), + word!("at"), + word!("last"), + punct!("."), + word!("ben", "Ben"), + word!("can"), + word!("see"), + word!("night"), + word!("sky"), + word!("and"), + word!("bright"), + word!("red"), + word!("camp"), + word!("lights"), + punct!("."), + word!("tim", "Tim"), + word!("and"), + word!("gus", "Gus"), + word!("grin"), + word!("and"), + word!("wave"), + word!("at"), + word!("camp"), + word!("at"), + word!("last"), + punct!("."), + word!("sam", "Sam"), + punct!(","), + word!("ben", "Ben"), + punct!(","), + word!("tim", "Tim"), + punct!(","), + word!("and"), + word!("gus", "Gus"), + word!("plan"), + word!("next"), + word!("big"), + word!("camp"), + word!("trip"), + punct!("."), +]; + +pub const READING_TEXTS: &[ReadingText] = &[ReadingText { + id: "basic-rules-01", + title: "Текст для чтения", + tokens: BASIC_RULES_TOKENS, +}]; + +pub fn word_by_id(id: &str) -> Option<&'static Word> { + DICTIONARY.iter().find(|word| word.id == id) +} + +#[cfg(test)] +pub fn tokens_to_text(tokens: &[Token]) -> String { + let mut output = String::new(); + let mut needs_space = false; + for token in tokens { + match token { + Token::Word { surface, .. } => { + if needs_space { + output.push(' '); + } + output.push_str(surface); + needs_space = true; + } + Token::Punctuation(value) => { + output.push_str(value); + needs_space = !matches!(*value, "…" | "—" | "("); + } + } + } + output +} + +#[cfg(test)] +mod tests { + use super::*; + use std::path::Path; + + fn source_text() -> &'static str { + let source = + include_str!("../../english/ex/theme-13-reading-rules/reading-text-01-basic-rules.md"); + source + .split_once("") + .unwrap() + .1 + .split_once("") + .unwrap() + .0 + .trim() + } + + #[test] + fn tokens_render_exact_source_text() { + let text = &READING_TEXTS[0]; + assert_eq!(tokens_to_text(text.tokens), source_text()); + assert_eq!( + text.tokens + .iter() + .filter(|token| matches!(token, Token::Word { .. })) + .count(), + 500 + ); + } + + #[test] + fn repeated_words_reuse_stable_ids() { + let sam_ids: Vec<_> = READING_TEXTS[0] + .tokens + .iter() + .filter_map(|token| match token { + Token::Word { word_id, surface } if *surface == "Sam" => Some(*word_id), + _ => None, + }) + .collect(); + assert!(sam_ids.len() > 1); + assert!(sam_ids.iter().all(|id| *id == "sam")); + } + + #[test] + fn dictionary_ids_are_unique_and_audio_files_exist() { + assert_eq!(DICTIONARY.len(), 97); + assert_eq!(word_by_id("camp").unwrap().ipa_us, "kæmp"); + assert!(word_by_id("missing").is_none()); + for (index, word) in DICTIONARY.iter().enumerate() { + assert!( + !DICTIONARY[..index] + .iter() + .any(|previous| previous.id == word.id), + "duplicate dictionary id: {}", + word.id + ); + } + for word in DICTIONARY { + let asset = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("public") + .join(word.audio_path.trim_start_matches('/')); + assert!(asset.is_file(), "missing audio: {}", asset.display()); + } + } + + #[test] + fn every_text_token_references_exactly_one_dictionary_word() { + for text in READING_TEXTS { + for token in text.tokens { + if let Token::Word { word_id, .. } = token { + let matches = DICTIONARY.iter().filter(|word| word.id == *word_id).count(); + assert_eq!(matches, 1, "{} references {word_id}", text.id); + } + } + } + } +} diff --git a/site/src/main.rs b/site/src/main.rs new file mode 100644 index 0000000..dbe866b --- /dev/null +++ b/site/src/main.rs @@ -0,0 +1,247 @@ +mod data; + +use data::{word_by_id, ReadingText, Token, Word, DICTIONARY, READING_TEXTS}; +use leptos::ev::KeyboardEvent; +use leptos::prelude::*; +use wasm_bindgen_futures::{spawn_local, JsFuture}; +use web_sys::HtmlInputElement; + +#[derive(Clone, Copy, PartialEq, Eq)] +enum AudioState { + Ready, + Playing, + PlaybackBlocked, + Unavailable, +} + +fn main() { + mount_to_body(App); +} + +#[component] +fn App() -> impl IntoView { + let reading_text = &READING_TEXTS[0]; + let word_count = reading_text + .tokens + .iter() + .filter(|token| matches!(token, Token::Word { .. })) + .count(); + let selected_id = RwSignal::new(None::<&'static str>); + let query = RwSignal::new(String::new()); + let audio_ref = NodeRef::::new(); + let audio_state = RwSignal::new(AudioState::Ready); + + let select_word = move |id: &'static str| { + if let Some(audio) = audio_ref.get() { + let _ = audio.pause(); + } + audio_state.set(AudioState::Ready); + selected_id.set(Some(id)); + }; + let activate_key = move |event: KeyboardEvent, id: &'static str| { + if event.key() == "Enter" || event.key() == " " { + event.prevent_default(); + select_word(id); + } + }; + + let toggle_audio = move |_| { + if let Some(audio) = audio_ref.get() { + if audio.paused() { + match audio.play() { + Ok(promise) => { + let audio_state = audio_state; + spawn_local(async move { + if JsFuture::from(promise).await.is_err() { + audio_state.set(AudioState::PlaybackBlocked); + } + }); + } + Err(_) => audio_state.set(AudioState::PlaybackBlocked), + } + } else { + let _ = audio.pause(); + } + } + }; + + view! { +
+
+

"Лаборатория чтения · Урок 01"

+

"Читаем" "по правилам"

+

{format!("{word_count} слов для спокойной тренировки. Нажмите на слово, чтобы увидеть его чтение.")}

+
+ +
+
+

"01"

+
+

{reading_text.title}

+

"Каждое слово — отдельная карточка для слуха и произношения."

+
+

{format!("{word_count} слов")}

+
+

+ {render_reading_text(reading_text, selected_id, select_word, activate_key)} +

+
+ +
+ {move || selected_id.get().and_then(word_by_id).map(|word| detail_view(word, audio_ref, audio_state, toggle_audio)).unwrap_or_else(|| view! { +
+

"Словарная карточка"

+

"Выберите слово в тексте"

+

"Карточка покажет написание, американское произношение и русскую подсказку."

+
+ }.into_any())} +
+ +
+
+

"02"

+
+

"Внутренний словарь"

+

"Все слова урока; поиск по написанию, IPA или русской подсказке."

+
+
+ + (&event).value()) + /> +
+ + + + {move || { + let needle = query.get().to_lowercase(); + DICTIONARY.iter().filter(|word| needle.is_empty() || word.spelling.contains(&needle) || word.ipa_us.contains(&needle) || word.russian_hint.to_lowercase().contains(&needle)).map(|word| { + let id = word.id; + view! { + + + + + + + } + }).collect_view() + }} + +
"Слово""US IPA""Подсказка""Аудио"
{word.ipa_us}{word.russian_hint} + +
+
+
+
+ } +} + +fn render_reading_text( + reading_text: &'static ReadingText, + selected_id: RwSignal>, + select_word: impl Fn(&'static str) + Copy + 'static, + activate_key: impl Fn(KeyboardEvent, &'static str) + Copy + 'static, +) -> AnyView { + reading_text + .tokens + .iter() + .enumerate() + .map(|(index, token)| match token { + Token::Word { word_id, surface } => { + let id = *word_id; + let leading_space = if index == 0 { "" } else { " " }; + view! { + + {leading_space} + + + } + .into_any() + } + Token::Punctuation(value) => { + view! { {*value} }.into_any() + } + }) + .collect_view() + .into_any() +} + +fn detail_view( + word: &'static Word, + audio_ref: NodeRef, + audio_state: RwSignal, + toggle_audio: impl Fn(leptos::ev::MouseEvent) + Copy + 'static, +) -> AnyView { + view! { +
+

"Словарная карточка"

+

{word.spelling}

+
+
"Американский IPA"
{word.ipa_us}
+
"Русская подсказка"
{word.russian_hint}
+
+
+ }.into_any() +} + +fn audio_button_label(state: AudioState, spelling: &str) -> String { + match state { + AudioState::Ready => format!("Слушать: {spelling}"), + AudioState::Playing => format!("Пауза: {spelling}"), + AudioState::PlaybackBlocked => format!("Повторить воспроизведение: {spelling}"), + AudioState::Unavailable => format!("Аудио недоступно: {spelling}"), + } +} + +fn audio_button_text(state: AudioState) -> &'static str { + match state { + AudioState::Ready => "Слушать", + AudioState::Playing => "Пауза", + AudioState::PlaybackBlocked => "Повторить", + AudioState::Unavailable => "Аудио недоступно", + } +} + +fn audio_status_text(state: AudioState) -> &'static str { + match state { + AudioState::Ready => "Запись: американский английский · MP3", + AudioState::Playing => "Воспроизводится: американский английский · MP3", + AudioState::PlaybackBlocked => "Браузер не разрешил начать запись. Нажмите «Повторить».", + AudioState::Unavailable => { + "Не удалось открыть локальный MP3. Проверьте файл и повторите попытку." + } + } +} diff --git a/site/style.css b/site/style.css new file mode 100644 index 0000000..1d6e383 --- /dev/null +++ b/site/style.css @@ -0,0 +1,84 @@ +:root { + --paper: #f4efe4; + --ink: #1c2722; + --forest: #174d3b; + --moss: #477650; + --coral: #c5533d; + --sun: #ecbc55; + --line: #c9c2b2; + --mist: #e6dfd1; + --surface: #fbf8f0; + --input: #fffdf8; + --ink-muted: #526159; + --forest-light: #7da58c; + --forest-pale: #bed0be; + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-5: 1.5rem; + --space-6: 2rem; + --space-7: 3rem; + --radius-sm: 0.25rem; + --radius-lg: 1rem; + --border-width: 1px; + --border-emphasis: 2px; + --shadow: 0.45rem 0.45rem 0 var(--ink); + --sans: "Trebuchet MS", "Segoe UI", sans-serif; + --serif: Georgia, "Times New Roman", serif; + --type-overline: 0.75rem; + --type-meta: 0.8rem; + --type-caption: 0.85rem; + --type-body: 1rem; + --type-lede: 1.15rem; + --type-word: clamp(1.25rem, 2vw, 1.65rem); + --type-detail: 1.4rem; + --type-heading: clamp(1.8rem, 4vw, 3.2rem); + --type-display: clamp(2.8rem, 8vw, 6.5rem); +} + +* { box-sizing: border-box; } +body { margin: 0; background: var(--paper); color: var(--ink); font-family: var(--sans); } +button, input { font: inherit; } +button { cursor: pointer; } +.lesson-shell { width: min(100% - var(--space-5), 76rem); margin: 0 auto; padding: var(--space-7) 0; } +.masthead { max-width: 46rem; border-left: var(--space-2) solid var(--coral); padding-left: var(--space-5); margin-bottom: var(--space-7); } +.eyebrow, .detail-kicker, .section-number { color: var(--forest); font-size: var(--type-overline); font-weight: 800; letter-spacing: 0.12em; margin: 0 0 var(--space-2); text-transform: uppercase; } +h1, h2, p { margin-top: 0; } +h1 { font-family: var(--serif); font-size: var(--type-display); font-weight: 400; line-height: 0.9; letter-spacing: -0.06em; margin-bottom: var(--space-4); } +h1 em { color: var(--coral); display: block; } +h2 { font-family: var(--serif); font-size: var(--type-heading); font-weight: 400; letter-spacing: -0.04em; margin-bottom: var(--space-2); } +.lede { font-size: var(--type-lede); line-height: 1.55; max-width: 36rem; } +.reading-card, .detail-panel, .dictionary-section { border: var(--border-width) solid var(--line); border-radius: var(--radius-lg); margin-bottom: var(--space-6); } +.reading-card { background: var(--surface); box-shadow: var(--shadow); padding: var(--space-6); } +.section-heading, .dictionary-heading { align-items: flex-start; display: flex; gap: var(--space-4); } +.section-heading > div, .dictionary-heading > div { flex: 1; } +.section-heading p:not(.section-number), .dictionary-heading p:not(.section-number) { color: var(--ink-muted); line-height: 1.5; } +.word-count { background: var(--sun); border-radius: 999px; font-size: var(--type-meta); font-weight: 800; margin: 0; padding: var(--space-2) var(--space-3); white-space: nowrap; } +.reading-text { font-family: var(--serif); font-size: var(--type-word); line-height: 2; margin: var(--space-6) 0 0; } +.reading-word { background: transparent; border: 0; border-bottom: var(--border-emphasis) solid transparent; color: inherit; font-family: inherit; font-size: inherit; line-height: inherit; padding: 0; transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease; } +.reading-word:hover, .reading-word:focus-visible, .reading-word.active { background: var(--sun); border-color: var(--coral); color: var(--ink); outline: none; } +.punctuation { white-space: pre; } +.detail-panel { background: var(--forest); color: var(--paper); min-height: 17rem; padding: var(--space-6); } +.detail-kicker { color: var(--sun); } +.detail-content h2 { color: var(--sun); } +.pronunciation-grid { display: grid; gap: var(--space-4); grid-template-columns: repeat(2, minmax(0, 1fr)); margin: var(--space-5) 0; } +.pronunciation-grid div { border-top: var(--border-width) solid var(--forest-light); padding-top: var(--space-2); } +dt { color: var(--forest-pale); font-size: var(--type-overline); font-weight: 800; letter-spacing: 0.08em; margin-bottom: var(--space-2); text-transform: uppercase; } +dd { font-family: var(--serif); font-size: var(--type-detail); margin: 0; } +.audio-button { background: var(--sun); border: var(--border-emphasis) solid var(--sun); border-radius: var(--radius-sm); color: var(--ink); font-weight: 800; padding: var(--space-3) var(--space-5); } +.audio-button:hover, .audio-button:focus-visible { background: transparent; color: var(--sun); outline: var(--border-emphasis) solid var(--sun); outline-offset: var(--space-1); } +.audio-button:disabled { background: transparent; border-color: var(--forest-light); color: var(--forest-pale); cursor: not-allowed; } +.audio-note { color: var(--forest-pale); font-size: var(--type-caption); margin: var(--space-3) 0 0; } +.detail-empty { max-width: 32rem; } +.dictionary-section { background: var(--mist); padding: var(--space-6); } +.search-label { display: block; font-size: var(--type-caption); font-weight: 800; margin: var(--space-5) 0 var(--space-2); } +input { background: var(--input); border: var(--border-width) solid var(--ink); border-radius: var(--radius-sm); color: var(--ink); padding: var(--space-3); width: min(100%, 34rem); } +input:focus-visible { outline: var(--space-1) solid var(--coral); outline-offset: var(--space-1); } +.table-wrap { margin-top: var(--space-5); overflow-x: auto; } +table { border-collapse: collapse; min-width: 38rem; width: 100%; } +th, td { border-bottom: var(--border-width) solid var(--line); padding: var(--space-3); text-align: left; } +th { color: var(--forest); font-size: var(--type-overline); letter-spacing: 0.08em; text-transform: uppercase; } +.table-word { background: none; border: 0; border-bottom: 1px solid var(--forest); color: var(--forest); font-weight: 800; padding: 0; } +.table-word:hover, .table-word:focus-visible { color: var(--coral); outline: none; } +@media (max-width: 38rem) { .lesson-shell { width: min(100% - var(--space-4), 76rem); padding: var(--space-5) 0; } .reading-card, .detail-panel, .dictionary-section { padding: var(--space-4); } .section-heading, .dictionary-heading { gap: var(--space-3); } .word-count { display: none; } .pronunciation-grid { grid-template-columns: 1fr; } }