diff options
Diffstat (limited to 'corp/russian')
-rw-r--r-- | corp/russian/README.md | 9 | ||||
-rw-r--r-- | corp/russian/predlozhnik/.gitignore | 3 | ||||
-rw-r--r-- | corp/russian/predlozhnik/Cargo.lock | 460 | ||||
-rw-r--r-- | corp/russian/predlozhnik/Cargo.toml | 12 | ||||
-rw-r--r-- | corp/russian/predlozhnik/default.nix | 52 | ||||
-rw-r--r-- | corp/russian/predlozhnik/index.css | 29 | ||||
-rw-r--r-- | corp/russian/predlozhnik/index.html | 24 | ||||
-rw-r--r-- | corp/russian/predlozhnik/src/main.rs | 345 |
8 files changed, 934 insertions, 0 deletions
diff --git a/corp/russian/README.md b/corp/russian/README.md new file mode 100644 index 000000000000..23c3d594c8de --- /dev/null +++ b/corp/russian/README.md @@ -0,0 +1,9 @@ +//corp/russian +============== + +This folder contains TVL corp projects related to the Russian +language, such as the code powering +[Предложник](https://predlozhnik.ru). + +Unless otherwise specified, all rights to these projects are reserved +by ООО "ТВЛ". diff --git a/corp/russian/predlozhnik/.gitignore b/corp/russian/predlozhnik/.gitignore new file mode 100644 index 000000000000..58eaf3e32687 --- /dev/null +++ b/corp/russian/predlozhnik/.gitignore @@ -0,0 +1,3 @@ +/target/ +**/*.rs.bk +dist/ diff --git a/corp/russian/predlozhnik/Cargo.lock b/corp/russian/predlozhnik/Cargo.lock new file mode 100644 index 000000000000..131aa134fec6 --- /dev/null +++ b/corp/russian/predlozhnik/Cargo.lock @@ -0,0 +1,460 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "boolinator" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" + +[[package]] +name = "bumpalo" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "gloo" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23947965eee55e3e97a5cd142dd4c10631cc349b48cecca0ed230fd296f568cd" +dependencies = [ + "gloo-console", + "gloo-dialogs", + "gloo-events", + "gloo-file", + "gloo-render", + "gloo-storage", + "gloo-timers", + "gloo-utils", +] + +[[package]] +name = "gloo-console" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" +dependencies = [ + "gloo-utils", + "js-sys", + "serde", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-dialogs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-events" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-file" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" +dependencies = [ + "gloo-events", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-render" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-storage" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" +dependencies = [ + "gloo-utils", + "js-sys", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-timers" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-utils" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40913a05c8297adca04392f707b1e73b12ba7b8eab7244a4961580b1fd34063c" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + +[[package]] +name = "predlozhnik" +version = "0.1.0" +dependencies = [ + "lazy_static", + "maplit", + "wasm-bindgen", + "yew", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "scoped-tls-hkt" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e9d7eaddb227e8fbaaa71136ae0e1e913ca159b86c7da82f3e8f0044ad3a63" + +[[package]] +name = "serde" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "syn" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "yew" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1ccb53e57d3f7d847338cf5758befa811cabe207df07f543c06f502f9998cd" +dependencies = [ + "console_error_panic_hook", + "gloo", + "gloo-utils", + "indexmap", + "js-sys", + "scoped-tls-hkt", + "slab", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "yew-macro", +] + +[[package]] +name = "yew-macro" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fab79082b556d768d6e21811869c761893f0450e1d550a67892b9bce303b7bb" +dependencies = [ + "boolinator", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] diff --git a/corp/russian/predlozhnik/Cargo.toml b/corp/russian/predlozhnik/Cargo.toml new file mode 100644 index 000000000000..90205bc4fb1b --- /dev/null +++ b/corp/russian/predlozhnik/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "predlozhnik" +version = "0.1.0" +edition = "2021" + +[dependencies] +maplit = "1.0" +lazy_static = "1.4" +yew = "0.19" + +# needs to be in sync with nixpkgs +wasm-bindgen = "= 0.2.83" diff --git a/corp/russian/predlozhnik/default.nix b/corp/russian/predlozhnik/default.nix new file mode 100644 index 000000000000..2137be111278 --- /dev/null +++ b/corp/russian/predlozhnik/default.nix @@ -0,0 +1,52 @@ +{ lib, pkgs, ... }: + +let + wasmRust = pkgs.rust-bin.stable.latest.default.override { + targets = [ "wasm32-unknown-unknown" ]; + }; + + cargoToml = with builtins; fromTOML (readFile ./Cargo.toml); + + wasmBindgenMatch = + cargoToml.dependencies.wasm-bindgen == "= ${pkgs.wasm-bindgen-cli.version}"; + + assertWasmBindgen = assert (lib.assertMsg wasmBindgenMatch '' + Due to instability in the Rust WASM ecosystem, the trunk build + tool enforces that the Cargo-dependency version of `wasm-bindgen` + MUST match the version of the CLI supplied in the environment. + + This can get out of sync when nixpkgs is updated. To resolve it, + wasm-bindgen must be bumped in the Cargo.toml file and cargo needs + to be run to resolve the dependencies. + + Versions of `wasm-bindgen` in Cargo.toml: + + Expected: '= ${pkgs.wasm-bindgen-cli.version}' + Actual: '${cargoToml.dependencies.wasm-bindgen}' + ''); pkgs.wasm-bindgen-cli; + + deps = with pkgs; [ + binaryen + sass + wasmRust + trunk + assertWasmBindgen + ]; + +in +pkgs.rustPlatform.buildRustPackage rec { + pname = "predlozhnik"; + version = "canon"; + src = lib.cleanSource ./.; + cargoLock.lockFile = ./Cargo.lock; + + buildPhase = '' + export PATH=${lib.makeBinPath deps}:$PATH + mkdir home + export HOME=$PWD/.home + env + trunk build --release -d $out + ''; + + dontInstall = true; +} diff --git a/corp/russian/predlozhnik/index.css b/corp/russian/predlozhnik/index.css new file mode 100644 index 000000000000..3529574c4f2b --- /dev/null +++ b/corp/russian/predlozhnik/index.css @@ -0,0 +1,29 @@ +body { + max-width: 800px; + margin: 40px auto; +} + +#header { + display: flex; + flex-direction: column; +} + +.btn.btn-ghost:disabled { + border-color: #9f9f9f; + color: #9f9f9f; +} + +#predlogi,#padezhi { + display: flex; + flex-direction: row; + flex-wrap: wrap; +} + +.btn { + margin: 3px; + flex-grow: 1; +} + +.footer { + text-align: right; +} diff --git a/corp/russian/predlozhnik/index.html b/corp/russian/predlozhnik/index.html new file mode 100644 index 000000000000..6af1adc0bfba --- /dev/null +++ b/corp/russian/predlozhnik/index.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" + href="https://unpkg.com/terminal.css@0.7.2/dist/terminal.min.css" /> + <link data-trunk rel="inline" href="index.css"> + <title>Предложник</title> + + <!-- Yandex.RTB --> + <script>window.yaContextCb=window.yaContextCb||[]</script> + <script src="https://yandex.ru/ads/system/context.js" async></script> + </head> + <body> + <noscript> + <h1>Предложник</h1> + <p> + ... показывает с какими падежами употребляются предлоги в + русском языке. Но, к сожалению, только с помощью Javascript. + </p> + </noscript> + </body> +</html> diff --git a/corp/russian/predlozhnik/src/main.rs b/corp/russian/predlozhnik/src/main.rs new file mode 100644 index 000000000000..e267c849de83 --- /dev/null +++ b/corp/russian/predlozhnik/src/main.rs @@ -0,0 +1,345 @@ +use yew::html::Scope; +use yew::prelude::*; + +use lazy_static::lazy_static; +use maplit::hashmap; +use std::collections::BTreeSet; +use std::collections::HashMap; + +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +enum Падеж { + Именительный, + Родительный, + Дательный, + Винительный, + Творительный, + Предложный, +} + +impl Падеж { + const ВСЕ: [Self; 6] = [ + Self::Именительный, + Self::Родительный, + Self::Дательный, + Self::Винительный, + Self::Творительный, + Self::Предложный, + ]; + + fn вопрос(&self) -> &str { + use Падеж::*; + match self { + Именительный => "кто? Что?", + Родительный => "кого? Чего?", + Дательный => "кому? Чему?", + Винительный => "кого? Что?", + Творительный => "кем? Чем?", + Предложный => "ком? Чём?", + } + } +} + +lazy_static! { + static ref ПО_ПРЕДЛОГУ: HashMap<&'static str, BTreeSet<Падеж>> = { + use Падеж::*; + + hashmap! { + "без" => BTreeSet::from([Родительный]), + "близ" => BTreeSet::from([Родительный]), + "в" => BTreeSet::from([Винительный, Предложный]), + "вместо" => BTreeSet::from([Родительный]), + "вне" => BTreeSet::from([Родительный]), + "внутри" => BTreeSet::from([Родительный]), + "возле" => BTreeSet::from([Родительный]), + "вокруг" => BTreeSet::from([Родительный]), + "вроде" => BTreeSet::from([Родительный]), + "для" => BTreeSet::from([Родительный]), + "до" => BTreeSet::from([Родительный]), + "за" => BTreeSet::from([Винительный, Творительный]), + "из" => BTreeSet::from([Родительный]), + "из-за" => BTreeSet::from([Родительный]), + "из-под" => BTreeSet::from([Родительный]), + "к" => BTreeSet::from([Дательный]), + "кроме" => BTreeSet::from([Родительный]), + "между" => BTreeSet::from([Творительный, Родительный]), + "на" => BTreeSet::from([Винительный, Предложный]), + "над" => BTreeSet::from([Творительный]), + "нет" => BTreeSet::from([Родительный]), + "о" => BTreeSet::from([Винительный, Предложный]), + "около" => BTreeSet::from([Родительный]), + "от" => BTreeSet::from([Родительный]), + "перед" => BTreeSet::from([Творительный]), + "по" => BTreeSet::from([Винительный, Дательный, Предложный]), + "под" => BTreeSet::from([Винительный, Творительный]), + "после" => BTreeSet::from([Родительный]), + "при" => BTreeSet::from([Предложный]), + "про" => BTreeSet::from([Винительный]), + "ради" => BTreeSet::from([Родительный]), + "с" => BTreeSet::from([Родительный, Винительный, Творительный]), + "сквозь" => BTreeSet::from([Винительный]), + "среди" => BTreeSet::from([Родительный]), + "у" => BTreeSet::from([Родительный]), + "через" => BTreeSet::from([Винительный]), + } + }; + static ref ПО_ПАДЕЖУ: HashMap<Падеж, BTreeSet<&'static str>> = { + let mut m = hashmap!(); + + for c in Падеж::ВСЕ { + let mut предлоги: BTreeSet<&'static str> = BTreeSet::new(); + for (k, v) in &*ПО_ПРЕДЛОГУ { + if v.contains(&c) { + предлоги.insert(k); + } + } + + m.insert(c, предлоги); + } + + m + }; + static ref ПАДЕЖИ: BTreeSet<Падеж> = BTreeSet::from(Падеж::ВСЕ); + static ref ПРЕДЛОГИ: BTreeSet<&'static str> = { + let mut s: BTreeSet<&'static str> = BTreeSet::new(); + + for п in ПО_ПРЕДЛОГУ.keys() { + s.insert(п); + } + + s + }; +} + +fn исключение(предлог: &str, падеж: Падеж) -> Option<Html> { + use Падеж::*; + + match (предлог, падеж) { + ("в", Винительный) => Some(html! {"Во что? В кого?"}), + + ("о", Винительный) => Some(html! { + <> + <p>{"О кого? Обо что?"}</p> + <p>{"Редко используется. Например:"}</p> + <ul> + <li>{"Удариться о притолоку."}</li> + <li>{"точить о камень."}</li> + </ul> + </> + }), + + ("между", Родительный) => Some(html! { + <> + <p>{"Между чего?"}</p> + <p>{"Редко используется. Только в идиомах и старой литературе:"}</p> + <ul> + <li>{"Читаю между строк."}</li> + </ul> + </> + }), + + _ => None, + } +} + +enum Сообщение { + ВыбралПадеж(Option<Падеж>), + ВыбралПредлог(Option<&'static str>), +} + +#[derive(Default)] +struct Модель { + падеж: Option<Падеж>, + предлог: Option<&'static str>, +} + +struct Вывод { + доступные_падежи: BTreeSet<Падеж>, + доступные_предлоги: BTreeSet<&'static str>, + объяснение: Option<Html>, +} + +fn объясни(падеж: Падеж, предлог: &str) -> Html { + let иск = match исключение(предлог, падеж) { + Some(exp) => html! { exp }, + None => html! { format!("{} {}", предлог, падеж.вопрос()) }, + }; + + html! { + <div id="obyasnenie"> + <hr/> + <h2>{"Пример:"}</h2> + {иск} + </div> + } +} + +fn ограничить(м: &Модель) -> Вывод { + match (м.падеж, &м.предлог) { + (Some(пж), Some(пл)) => Вывод { + доступные_падежи: (*ПО_ПРЕДЛОГУ)[пл].clone(), + доступные_предлоги: (*ПО_ПАДЕЖУ)[&пж].clone(), + объяснение: Some(объясни(пж, пл)), + }, + + (Some(пж), None) => Вывод { + доступные_падежи: BTreeSet::from([пж]), + доступные_предлоги: (*ПО_ПАДЕЖУ)[&пж].clone(), + объяснение: None, + }, + + (None, Some(пл)) => Вывод { + доступные_падежи: (*ПО_ПРЕДЛОГУ)[пл].clone(), + доступные_предлоги: BTreeSet::from([*пл]), + объяснение: None, + }, + + (None, None) => Вывод { + доступные_падежи: ПАДЕЖИ.clone(), + доступные_предлоги: ПРЕДЛОГИ.clone(), + объяснение: None, + }, + } +} + +fn класс_кнопки(выбран: bool, доступен: bool) -> String { + let класс = "btn ".to_string(); + класс + + match (выбран, доступен) { + (true, _) => "btn-primary", + (false, true) => "btn-ghost btn-primary", + (false, false) => "btn-ghost btn-default", + } +} + +fn покажи_предлог( + link: &Scope<Модель>, + м: &Модель, + вв: &Вывод, + п: &'static str, +) -> Html { + let выбран = м.предлог == Some(п); + let доступен = вв.доступные_предлоги.contains(п); + let класс = класс_кнопки(выбран, доступен); + + html! { + <button class={класс} + onclick={link.callback(move |_| if выбран { + Сообщение::ВыбралПредлог(None) + } else { + Сообщение::ВыбралПредлог(Some(п)) + })} + disabled={!доступен}> + {п} + </button> + } +} + +fn покажи_падеж( + link: &Scope<Модель>, м: &Модель, вв: &Вывод, п: Падеж +) -> Html { + let выбран = м.падеж == Some(п); + let доступен = вв.доступные_падежи.contains(&п); + let класс = класс_кнопки(выбран, доступен); + + html! { + <button class={класс} + onclick={link.callback(move |_| if выбран { + Сообщение::ВыбралПадеж(None) + } else { + Сообщение::ВыбралПадеж(Some(п)) + })} + disabled={!доступен}> + {format!("{:?}", п)} + </button> + } +} + +impl Component for Модель { + type Message = Сообщение; + type Properties = (); + + fn create(_ctx: &Context<Self>) -> Self { + Default::default() + } + + fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool { + match msg { + Сообщение::ВыбралПадеж(пж) => self.падеж = пж, + Сообщение::ВыбралПредлог(пл) => self.предлог = пл, + } + + true + } + + fn view(&self, ctx: &Context<Self>) -> Html { + let вв = ограничить(self); + let link = ctx.link(); + + let кнопки_предлогов = ПРЕДЛОГИ + .iter() + .map(|п| покажи_предлог(link, self, &вв, п)) + .collect::<Html>(); + + let кнопки_падежов = ПАДЕЖИ + .iter() + .map(|п| покажи_падеж(link, self, &вв, *п)) + .collect::<Html>(); + + let объяснение = вв.объяснение.map(|exp| exp).unwrap_or_else(|| html! {}); + + let footer = html! { + <footer> + <hr/> + <p class="footer"> + <a href="https://code.tvl.fyi/tree/users/tazjin/predlozhnik">{"код"}</a> + {" | "} + {"сделано "}<a href="https://tvl.su">{"ООО \"ТВЛ\""}</a> + </p> + </footer> + }; + + let код_рекламы = r#" +window.yaContextCb.push(()=>{ + Ya.Context.AdvManager.render({ + renderTo: 'yandex_rtb_R-A-1773485-1', + blockId: 'R-A-1773485-1' + }) +}) +"#; + + let реклама = html! { + <div id="ad"> + <div id="yandex_rtb_R-A-1773485-1"></div> + <script>{код_рекламы}</script> + </div> + }; + + html! { + <> + <div id="header"> + <h1>{"Предложник"}</h1> + <p>{"... показывает с какими падежами употребляются предлоги в русском языке."}</p> + </div> + + <h2>{"Выбирай предлог:"}</h2> + <div id="predlogi"> + {кнопки_предлогов} + </div> + <hr/> + + <h2>{"Выбирай падеж:"}</h2> + <div id="padezhi"> + {кнопки_падежов} + </div> + + {объяснение} + {footer} + {реклама} + </> + } + } +} + +fn main() { + yew::start_app::<Модель>(); +} |