From 6eedb1826ad8aa636883191215017b3f5496f057 Mon Sep 17 00:00:00 2001 From: Sebastian Moser Date: Sun, 1 Nov 2026 14:49:38 +0100 Subject: [PATCH] ppc login works in mme main --- Cargo.lock | 1234 ++++++++++++++--- Cargo.toml | 6 +- apps/os/src/generated.rs | 6 +- apps/os/src/main.rs | 2 +- core/src/config.rs | 24 +- core/src/error.rs | 2 +- core/src/instance/mod.rs | 104 +- core/src/instance/subscription.rs | 2 +- core/src/instance/updater.rs | 2 +- core/src/item.rs | 19 +- core/src/lib.rs | 36 +- core/src/memstore.rs | 3 +- core/src/platform/os/fsstore.rs | 21 +- core/src/platform/os/logging.rs | 191 ++- core/src/platform/os/mod.rs | 58 +- core/src/platform/os/unix_socket.rs | 2 +- core/src/platform/os/windows_socket.rs | 224 +++ flake.nix | 18 +- macros/src/lib.rs | 98 +- md | 149 -- parts/auth.client/Cargo.toml | 39 + parts/auth.client/generated/Cargo.toml | 11 + parts/auth.client/generated/src/lib.rs | 92 ++ parts/auth.client/part | 2 + .../src/client.rs => auth.client/src/lib.rs} | 205 +-- parts/auth/src/lib.rs | 6 - parts/cli/src/lib.rs | 8 +- parts/mize.dev/docker/base/Dockerfile | 32 + parts/mize.dev/docker/darwin/Dockerfile | 8 + parts/mize.dev/src/codegen.rs | 398 +++++- parts/mize.dev/src/generated.rs | 8 +- parts/mize.dev/src/lib.rs | 30 +- parts/mize.ui/dioxus-components/Cargo.toml | 3 +- .../dioxus-components/assets/theme.css | 44 - .../src/components/avatar/component.rs | 111 +- .../src/components/avatar/style.css | 84 -- .../src/components/badge/component.rs | 48 +- .../src/components/badge/style.css | 37 - .../src/components/button/component.rs | 202 ++- .../src/components/button/style.css | 195 --- .../src/components/card/component.rs | 83 +- .../src/components/card/style.css | 52 - .../src/components/checkbox/component.rs | 43 +- .../src/components/checkbox/style.css | 34 - .../src/components/control/component.rs | 211 +++ .../src/components/control/mod.rs | 2 + .../src/components/dialog/component.rs | 117 +- .../src/components/dialog/style.css | 100 -- .../src/components/input/component.rs | 47 +- .../src/components/input/style.css | 40 - .../src/components/label/component.rs | 16 +- .../src/components/label/style.css | 9 - .../dioxus-components/src/components/mod.rs | 4 + .../src/components/prompt/component.rs | 103 ++ .../src/components/prompt/mod.rs | 2 + .../src/components/scroll_area/style.css | 1 - .../src/components/separator/component.rs | 20 +- .../src/components/separator/style.css | 13 - .../src/components/switch/component.rs | 50 +- .../src/components/switch/style.css | 41 - .../src/components/textarea/component.rs | 91 +- .../src/components/textarea/style.css | 84 -- parts/mize.ui/dioxus-components/src/lib.rs | 79 +- parts/{auth => mme}/Cargo.toml | 14 +- parts/mme/src/dashboard.rs | 389 ++++++ parts/mme/src/generated.rs | 83 ++ parts/mme/src/lib.rs | 97 ++ parts/mos/Cargo.toml | 1 + 68 files changed, 4123 insertions(+), 1467 deletions(-) create mode 100644 core/src/platform/os/windows_socket.rs delete mode 100755 md create mode 100644 parts/auth.client/Cargo.toml create mode 100644 parts/auth.client/generated/Cargo.toml create mode 100644 parts/auth.client/generated/src/lib.rs create mode 100644 parts/auth.client/part rename parts/{auth/src/client.rs => auth.client/src/lib.rs} (83%) delete mode 100644 parts/auth/src/lib.rs create mode 100644 parts/mize.dev/docker/base/Dockerfile create mode 100644 parts/mize.dev/docker/darwin/Dockerfile delete mode 100644 parts/mize.ui/dioxus-components/assets/theme.css delete mode 100644 parts/mize.ui/dioxus-components/src/components/avatar/style.css delete mode 100644 parts/mize.ui/dioxus-components/src/components/badge/style.css delete mode 100644 parts/mize.ui/dioxus-components/src/components/button/style.css delete mode 100644 parts/mize.ui/dioxus-components/src/components/card/style.css delete mode 100644 parts/mize.ui/dioxus-components/src/components/checkbox/style.css create mode 100644 parts/mize.ui/dioxus-components/src/components/control/component.rs create mode 100644 parts/mize.ui/dioxus-components/src/components/control/mod.rs delete mode 100644 parts/mize.ui/dioxus-components/src/components/dialog/style.css delete mode 100644 parts/mize.ui/dioxus-components/src/components/input/style.css delete mode 100644 parts/mize.ui/dioxus-components/src/components/label/style.css create mode 100644 parts/mize.ui/dioxus-components/src/components/prompt/component.rs create mode 100644 parts/mize.ui/dioxus-components/src/components/prompt/mod.rs delete mode 100644 parts/mize.ui/dioxus-components/src/components/scroll_area/style.css delete mode 100644 parts/mize.ui/dioxus-components/src/components/separator/style.css delete mode 100644 parts/mize.ui/dioxus-components/src/components/switch/style.css delete mode 100644 parts/mize.ui/dioxus-components/src/components/textarea/style.css rename parts/{auth => mme}/Cargo.toml (55%) create mode 100644 parts/mme/src/dashboard.rs create mode 100644 parts/mme/src/generated.rs create mode 100644 parts/mme/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 96c05de..0688546 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,15 @@ dependencies = [ "equator", ] +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "1.0.0" @@ -106,83 +115,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bc62ac97cc33321f50863d514c3bc38a453947a8f9e781137e47c7401020aed" -[[package]] -name = "arborium" -version = "2.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "230e826fe3204178030e420751396c99431e4611fc67af63baf7767b4317bd75" -dependencies = [ - "arborium-css", - "arborium-highlight", - "arborium-rust", - "arborium-theme", - "arborium-tree-sitter", - "dlmalloc", -] - -[[package]] -name = "arborium-css" -version = "2.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3bf02fc773bafaac2cdc27862d6eb52e86927e740c69e0d87b4123f2589b9af" -dependencies = [ - "arborium-sysroot", - "cc", - "tree-sitter-language", -] - -[[package]] -name = "arborium-highlight" -version = "2.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee400d694bd935c513c50f9b1fda469b6d9cd192d80fede7bfa9e5851a54cb8" -dependencies = [ - "arborium-theme", - "arborium-tree-sitter", - "streaming-iterator", -] - -[[package]] -name = "arborium-rust" -version = "2.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8471397c67c4164b93d6a23ae80fb5b7af5dcc00fa9b143015efb1ea927ca8da" -dependencies = [ - "arborium-sysroot", - "cc", - "tree-sitter-language", -] - -[[package]] -name = "arborium-sysroot" -version = "2.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd9d120dd5df8b918cd96676a88f1233a66f10687d415b69f70b3396acddddf" -dependencies = [ - "cc", - "dlmalloc", -] - -[[package]] -name = "arborium-theme" -version = "2.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "042f9d025c80b2e625b4f0f10eda56a652444ef916025e855a292937bb8a949a" - -[[package]] -name = "arborium-tree-sitter" -version = "2.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd8de97695c76508ab780e03bd1db009f5db8567c985f5da5ae91a2ad57ef2bc" -dependencies = [ - "arborium-sysroot", - "cc", - "regex", - "regex-syntax", - "streaming-iterator", - "tree-sitter-language", -] - [[package]] name = "arg_enum_proc_macro" version = "0.3.4" @@ -369,8 +301,8 @@ dependencies = [ "bytes", "form_urlencoded", "futures-util", - "http", - "http-body", + "http 1.5.0", + "http-body 1.1.0", "http-body-util", "itoa", "matchit", @@ -383,7 +315,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.2", "tower", "tower-layer", "tower-service", @@ -397,16 +329,28 @@ checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", - "http", - "http-body", + "http 1.5.0", + "http-body 1.1.0", "http-body-util", "mime", "pin-project-lite", - "sync_wrapper", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -419,6 +363,12 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + [[package]] name = "bit_field" version = "0.10.3" @@ -473,6 +423,15 @@ dependencies = [ "objc2", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "built" version = "0.8.1" @@ -621,6 +580,20 @@ dependencies = [ "encoding_rs", ] +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link 0.2.1", +] + [[package]] name = "ciborium" version = "0.2.2" @@ -717,7 +690,7 @@ dependencies = [ "bitflags 2.13.1", "block", "cocoa-foundation", - "core-foundation", + "core-foundation 0.10.1", "core-graphics 0.24.0", "foreign-types 0.5.0", "libc", @@ -732,7 +705,7 @@ checksum = "81411967c50ee9a1fc11365f8c585f863a22a9697c89239c452292c40ba79b0d" dependencies = [ "bitflags 2.13.1", "block", - "core-foundation", + "core-foundation 0.10.1", "core-graphics-types", "objc", ] @@ -779,6 +752,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "const-serialize" version = "0.7.2" @@ -910,6 +889,16 @@ dependencies = [ "url", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -933,7 +922,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ "bitflags 2.13.1", - "core-foundation", + "core-foundation 0.10.1", "core-graphics-types", "foreign-types 0.5.0", "libc", @@ -946,7 +935,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ "bitflags 2.13.1", - "core-foundation", + "core-foundation 0.10.1", "core-graphics-types", "foreign-types 0.5.0", "libc", @@ -959,7 +948,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ "bitflags 2.13.1", - "core-foundation", + "core-foundation 0.10.1", "libc", ] @@ -1036,6 +1025,18 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.7" @@ -1073,6 +1074,33 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if 1.0.4", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "daemonize" version = "0.5.0" @@ -1088,8 +1116,18 @@ version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed17f5901b6630b993ca003def43f2f8ef4014fc13b047b57aad617ff32bc2ec" +dependencies = [ + "darling_core 0.24.1", + "darling_macro 0.24.1", ] [[package]] @@ -1105,17 +1143,41 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "darling_core" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6837e2cf7485aaae18f86181d2f0e9a7ed297a025e220aeabf63fdebd3a2ddff" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 3.0.5", +] + [[package]] name = "darling_macro" version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ - "darling_core", + "darling_core 0.21.3", "quote", "syn 2.0.119", ] +[[package]] +name = "darling_macro" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785" +dependencies = [ + "darling_core 0.24.1", + "quote", + "syn 3.0.5", +] + [[package]] name = "data-encoding" version = "2.11.1" @@ -1153,11 +1215,25 @@ dependencies = [ "thiserror 2.0.20", ] +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e" +dependencies = [ + "serde_core", +] [[package]] name = "derive_more" @@ -1202,7 +1278,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -1240,7 +1318,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84235ff0e272f15d4537603cdd50df6d45d50e51bb96326dbc0bdfd01d825226" dependencies = [ "dioxus-cli-config", - "http", + "http 1.5.0", "infer", "jni 0.21.1", "js-sys", @@ -1274,40 +1352,11 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "dioxus-code" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859cbf40e5da690df269d4d1ab01b4ec9921b408cec4cabce2dd1620cc15670e" -dependencies = [ - "arborium", - "arborium-theme", - "arborium-tree-sitter", - "dioxus", - "dioxus-code-macro", -] - -[[package]] -name = "dioxus-code-macro" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8654ef9b81bb051546b772cfd709401055a1460b3e8fb26d7847b040498354d0" -dependencies = [ - "arborium", - "arborium-theme", - "macro-string", - "proc-macro-crate 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "dioxus-components" version = "0.1.0" dependencies = [ "dioxus", - "dioxus-code", "dioxus-icons", "dioxus-primitives", ] @@ -1380,7 +1429,7 @@ dependencies = [ "base64 0.22.1", "bytes", "cocoa", - "core-foundation", + "core-foundation 0.10.1", "dioxus-asset-resolver", "dioxus-cli-config", "dioxus-core", @@ -1506,13 +1555,13 @@ dependencies = [ "futures-util", "gloo-net", "headers", - "http", - "http-body", + "http 1.5.0", + "http-body 1.1.0", "http-body-util", "js-sys", "mime", "pin-project", - "reqwest", + "reqwest 0.12.28", "rustversion", "send_wrapper", "serde", @@ -1549,7 +1598,7 @@ dependencies = [ "futures-channel", "futures-util", "generational-box", - "http", + "http 1.5.0", "inventory", "parking_lot", "serde", @@ -1839,17 +1888,6 @@ dependencies = [ "syn 3.0.5", ] -[[package]] -name = "dlmalloc" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad5208a115eaba24916f7456929832e310a81518c641f93fee4f89aa93aa3675" -dependencies = [ - "cfg-if 1.0.4", - "libc", - "windows-sys 0.61.2", -] - [[package]] name = "dlopen2" version = "0.8.2" @@ -1915,12 +1953,71 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + [[package]] name = "either" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "encoding_rs" version = "0.8.44" @@ -1950,7 +2047,7 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60587c2044cabd91c4d4c73e3912e9f1ea7d76905f31c7eec51869305dae044" dependencies = [ - "darling", + "darling 0.21.3", "proc-macro2", "quote", "syn 2.0.119", @@ -2074,6 +2171,22 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "field-offset" version = "0.3.6" @@ -2395,6 +2508,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -2573,7 +2687,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http", + "http 1.5.0", "js-sys", "pin-project", "serde", @@ -2620,6 +2734,17 @@ dependencies = [ "system-deps", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "gtk" version = "0.18.2" @@ -2672,6 +2797,25 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.14.2", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "2.7.1" @@ -2683,6 +2827,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.17.1" @@ -2698,7 +2848,7 @@ dependencies = [ "base64 0.22.1", "bytes", "headers-core", - "http", + "http 1.5.0", "httpdate", "mime", "sha1", @@ -2710,7 +2860,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http", + "http 1.5.0", ] [[package]] @@ -2725,6 +2875,30 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "home" version = "0.5.12" @@ -2746,6 +2920,17 @@ dependencies = [ "match_token", ] +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http" version = "1.5.0" @@ -2756,6 +2941,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.1.0" @@ -2763,7 +2959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" dependencies = [ "bytes", - "http", + "http 1.5.0", ] [[package]] @@ -2774,8 +2970,8 @@ checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" dependencies = [ "bytes", "futures-core", - "http", - "http-body", + "http 1.5.0", + "http-body 1.1.0", "pin-project-lite", ] @@ -2785,8 +2981,8 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92208b0986f414edaca8ede2c6962c979309346a9e8e19d07d0a7879aae1549e" dependencies = [ - "rustls", - "rustls-pemfile", + "rustls 0.23.43", + "rustls-pemfile 2.2.0", "rustls-pki-types", "unicase", "webpki", @@ -2805,6 +3001,30 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.12.0" @@ -2814,8 +3034,8 @@ dependencies = [ "atomic-waker", "bytes", "futures-core", - "http", - "http-body", + "http 1.5.0", + "http-body 1.1.0", "httparse", "itoa", "pin-project-lite", @@ -2824,18 +3044,32 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-rustls" version = "0.27.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53" dependencies = [ - "http", - "hyper", + "http 1.5.0", + "hyper 1.12.0", "hyper-util", - "rustls", + "rustls 0.23.43", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.6", "tower-service", "webpki-roots 1.0.9", ] @@ -2850,20 +3084,44 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http", - "http-body", + "http 1.5.0", + "http-body 1.1.0", "httparse", - "hyper", + "hyper 1.12.0", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.5", "tokio", "tower-service", "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.61.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "2.4.0" @@ -3014,6 +3272,17 @@ version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e44b0a4eaa4c82f441d50a963f2d5f05a787240aeee097597033e72accfd22f" +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + [[package]] name = "indexmap" version = "2.14.2" @@ -3021,7 +3290,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.17.1", + "serde", + "serde_core", ] [[package]] @@ -3070,6 +3341,15 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -3117,10 +3397,12 @@ dependencies = [ "defmt", "jiff-core", "jiff-static", + "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", "serde_core", + "windows-link 0.2.1", ] [[package]] @@ -3144,6 +3426,21 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "jiff-tzdb" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8377070c6bae868759445e5a77f66d84f0b72f3a054bfb00e6d038b8282da7" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + [[package]] name = "jni" version = "0.21.1" @@ -3273,7 +3570,7 @@ checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" dependencies = [ "cssparser", "html5ever", - "indexmap", + "indexmap 2.14.2", "selectors", ] @@ -3288,6 +3585,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "lebe" @@ -3703,6 +4003,13 @@ dependencies = [ "tracing", ] +[[package]] +name = "mize-generated-auth" +version = "0.1.0" +dependencies = [ + "mize", +] + [[package]] name = "mize-obsidian-plugin" version = "0.1.0" @@ -3711,11 +4018,19 @@ dependencies = [ ] [[package]] -name = "mize-part-auth" +name = "mize-part-auth-client" version = "0.1.0" dependencies = [ + "chrono", "log", "mize", + "mize-generated-auth", + "openidconnect", + "reqwest 0.11.27", + "serde", + "serde_json", + "tokio", + "webbrowser", ] [[package]] @@ -3737,9 +4052,16 @@ dependencies = [ ] [[package]] -name = "mize-part-mos" +name = "mize-part-mize-ui" +version = "0.1.0" + +[[package]] +name = "mize-part-mme" version = "0.1.0" dependencies = [ + "dioxus", + "dioxus-components", + "dioxus-icons", "log", "mize", ] @@ -3794,7 +4116,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 1.5.0", "httparse", "memchr", "mime", @@ -3930,6 +4252,22 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.8", + "smallvec", + "zeroize", +] + [[package]] name = "num-complex" version = "0.4.6" @@ -3966,6 +4304,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -3984,6 +4332,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -4017,6 +4366,26 @@ dependencies = [ "libc", ] +[[package]] +name = "oauth2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" +dependencies = [ + "base64 0.22.1", + "chrono", + "getrandom 0.2.17", + "http 1.5.0", + "rand 0.8.8", + "reqwest 0.12.28", + "serde", + "serde_json", + "serde_path_to_error", + "sha2", + "thiserror 1.0.69", + "url", +] + [[package]] name = "objc" version = "0.2.7" @@ -4144,6 +4513,37 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "openidconnect" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c6709ba2ea764bbed26bce1adf3c10517113ddea6f2d4196e4851757ef2b2" +dependencies = [ + "base64 0.21.7", + "chrono", + "dyn-clone", + "ed25519-dalek", + "hmac", + "http 1.5.0", + "itertools 0.10.5", + "log", + "oauth2", + "p256", + "p384", + "rand 0.8.8", + "rsa", + "serde", + "serde-value", + "serde_json", + "serde_path_to_error", + "serde_plain", + "serde_with", + "sha2", + "subtle", + "thiserror 1.0.69", + "url", +] + [[package]] name = "openssl" version = "0.10.81" @@ -4193,6 +4593,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "os_pipe" version = "1.2.3" @@ -4203,6 +4612,30 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "palette" version = "0.7.7" @@ -4293,6 +4726,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -4463,6 +4905,27 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.34" @@ -4546,6 +5009,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -4716,8 +5188,8 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.1.3", - "rustls", - "socket2", + "rustls 0.23.43", + "socket2 0.6.5", "thiserror 2.0.20", "tokio", "tracing", @@ -4737,7 +5209,7 @@ dependencies = [ "rand_pcg 0.10.2", "ring", "rustc-hash 2.1.3", - "rustls", + "rustls 0.23.43", "rustls-pki-types", "slab", "thiserror 2.0.20", @@ -4755,7 +5227,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2", + "socket2 0.6.5", "tracing", "windows-sys 0.61.2", ] @@ -4933,7 +5405,7 @@ dependencies = [ "built", "cfg-if 1.0.4", "interpolate_name", - "itertools", + "itertools 0.14.0", "libc", "libfuzzer-sys", "log", @@ -5033,6 +5505,26 @@ dependencies = [ "thiserror 2.0.20", ] +[[package]] +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + [[package]] name = "regex" version = "1.13.1" @@ -5062,6 +5554,47 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-rustls 0.24.2", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", + "tokio", + "tokio-rustls 0.24.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg", +] + [[package]] name = "reqwest" version = "0.12.28" @@ -5074,11 +5607,11 @@ dependencies = [ "cookie_store", "futures-core", "futures-util", - "http", - "http-body", + "http 1.5.0", + "http-body 1.1.0", "http-body-util", - "hyper", - "hyper-rustls", + "hyper 1.12.0", + "hyper-rustls 0.27.10", "hyper-util", "js-sys", "log", @@ -5086,14 +5619,14 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls", + "rustls 0.23.43", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.2", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.6", "tokio-util", "tower", "tower-http", @@ -5106,6 +5639,16 @@ dependencies = [ "webpki-roots 1.0.9", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "rfd" version = "0.17.2" @@ -5150,6 +5693,26 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -5184,6 +5747,18 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.43" @@ -5195,11 +5770,20 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.15", "subtle", "zeroize", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -5219,6 +5803,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.103.15" @@ -5261,12 +5855,60 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab508826f74a77ca9d5aba6ff19b522583ee3eaf28a19384ff3d0e5835fadf6e" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "3.7.0" @@ -5274,7 +5916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags 2.13.1", - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -5333,6 +5975,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde-wasm-bindgen" version = "0.6.5" @@ -5388,6 +6040,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_plain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" +dependencies = [ + "serde", +] + [[package]] name = "serde_qs" version = "0.15.0" @@ -5431,6 +6092,39 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9adc193c780ef8f159aee8b61e2d5801aaa555e6eb0947fe45530ec506296f" +dependencies = [ + "base64 0.23.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.2", + "jiff", + "schemars 0.9.0", + "schemars 1.2.3", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e17bbc68e28663bbbb90df47e058aa7eda4fb445b89fe70457bb94fbccf6e49" +dependencies = [ + "darling 0.24.1", + "proc-macro2", + "quote", + "syn 3.0.5", +] + [[package]] name = "servo_arc" version = "0.2.0" @@ -5498,6 +6192,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + [[package]] name = "simd-adler32" version = "0.3.10" @@ -5592,6 +6296,16 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9be42f50aa861c555654aa3a37f52f4b1074bacf4e48fe0ef7fa584e80f1f0f" +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socket2" version = "0.6.5" @@ -5637,18 +6351,22 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520" - [[package]] name = "string_cache" version = "0.8.9" @@ -5747,6 +6465,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -5782,6 +6506,27 @@ dependencies = [ "windows 0.52.0", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "system-deps" version = "6.2.2" @@ -5803,7 +6548,7 @@ checksum = "9103edf55f2da3c82aea4c7fab7c4241032bfeea0e71fa557d98e00e7ce7cc20" dependencies = [ "bitflags 2.13.1", "block2", - "core-foundation", + "core-foundation 0.10.1", "core-graphics 0.25.0", "crossbeam-channel", "dispatch2", @@ -6008,7 +6753,7 @@ dependencies = [ "libc", "mio", "pin-project-lite", - "socket2", + "socket2 0.6.5", "tokio-macros", "windows-sys 0.61.2", ] @@ -6024,13 +6769,23 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db" dependencies = [ - "rustls", + "rustls 0.23.43", "tokio", ] @@ -6086,7 +6841,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap", + "indexmap 2.14.2", "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -6097,7 +6852,7 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap", + "indexmap 2.14.2", "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -6108,7 +6863,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap", + "indexmap 2.14.2", "serde", "serde_spanned", "toml_datetime 0.6.11", @@ -6122,7 +6877,7 @@ version = "0.25.17+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c" dependencies = [ - "indexmap", + "indexmap 2.14.2", "toml_datetime 1.1.2+spec-1.1.0", "toml_parser", "winnow 1.0.4", @@ -6152,7 +6907,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper", + "sync_wrapper 1.0.2", "tokio", "tower-layer", "tower-service", @@ -6167,8 +6922,8 @@ dependencies = [ "bitflags 2.13.1", "bytes", "futures-util", - "http", - "http-body", + "http 1.5.0", + "http-body 1.1.0", "pin-project-lite", "tower", "tower-layer", @@ -6281,12 +7036,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "tree-sitter-language" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0af592be68c579aa78a16846bd19422978c3c52e438523d45ff5d1bff1f9d4a" - [[package]] name = "try-lock" version = "0.2.5" @@ -6301,7 +7050,7 @@ checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d" dependencies = [ "bytes", "data-encoding", - "http", + "http 1.5.0", "httparse", "log", "rand 0.9.5", @@ -6318,12 +7067,12 @@ checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", - "http", + "http 1.5.0", "httparse", "log", "native-tls", "rand 0.9.5", - "rustls", + "rustls 0.23.43", "sha1", "thiserror 2.0.20", "utf-8", @@ -6375,6 +7124,7 @@ dependencies = [ "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -6669,6 +7419,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "webpki-roots" version = "0.26.11" @@ -6908,6 +7664,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -6959,6 +7724,21 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -7016,6 +7796,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -7034,6 +7820,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -7052,6 +7844,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -7082,6 +7880,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -7100,6 +7904,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -7118,6 +7928,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -7136,6 +7952,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -7175,6 +7997,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if 1.0.4", + "windows-sys 0.48.0", +] + [[package]] name = "wit-bindgen" version = "0.57.1" @@ -7202,7 +8034,7 @@ dependencies = [ "dunce", "gtk", "html5ever", - "http", + "http 1.5.0", "javascriptcore-rs", "jni 0.21.1", "kuchikiki", diff --git a/Cargo.toml b/Cargo.toml index 5a7291f..b270162 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,13 +8,13 @@ members = [ "parts/mize.ui/dioxus-components", ] exclude = [ - "parts/mize.ui", - "parts/mize.ui/upstream", - "parts/mize.ui/fluxer", + "parts/mos", + # "parts/mme", ] default-members = [ "apps/obsidian-plugin", "apps/os", + "parts/*", ] resolver = "2" diff --git a/apps/os/src/generated.rs b/apps/os/src/generated.rs index f36c1e0..ab9764b 100644 --- a/apps/os/src/generated.rs +++ b/apps/os/src/generated.rs @@ -6,8 +6,8 @@ pub struct CliPart { } impl MizePart for CliPart { - fn id(&self) -> MizeId { - self.id.clone() + fn id(&self) -> MizeResult { + Ok(self.id.clone()) } } @@ -15,7 +15,7 @@ impl CliPart { pub fn get(name: &str) -> MizeResult { let mut mize = get_global_mize()?; let part = mize.get_part(name)?; - Ok(CliPart { id: part.id() }) + Ok(CliPart { id: part.id()? }) } pub fn run(&self, cmdline: Vec) -> MizeResult<()> { let cmdline = cmdline.into_item_data(); diff --git a/apps/os/src/main.rs b/apps/os/src/main.rs index f19df6e..3bce146 100644 --- a/apps/os/src/main.rs +++ b/apps/os/src/main.rs @@ -57,7 +57,7 @@ fn tried_main() -> MizeResult<()> { let cli_matches = cli_matches(); // logging - init_logger(&cli_matches); + init_logger(Some(&cli_matches)); // init mize let mut mize = Mize::with_config(config_from_cli_args(&cli_matches)?)?; diff --git a/core/src/config.rs b/core/src/config.rs index 9ab4c71..0de921a 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -59,13 +59,13 @@ impl ConfigOptId { opt.fun = Some(fun); self.clone() } - pub fn method MizeResult + Send + Sync + 'static>(self, name: &str, fun: F) -> ConfigOptId { + pub fn method MizeResult + Send + Sync + 'static>(self, name: &str, signature: &str, fun: F) -> ConfigOptId { let mize = get_global_mize().unwrap(); let mut cur_part = self.id.clone(); let id = cur_part.join(name).unwrap(); // in generate mode: record method metadata, skip normal registration if mize.is_generate_mode().unwrap_or(false) { - mize.record_method(name, id.clone(), "method").ok(); + mize.record_method(name, id.clone(), "method", signature).ok(); return self.clone(); } let mut opts = mize.config_opts.lock().unwrap(); @@ -118,13 +118,13 @@ pub fn opt(name: &str) -> crate::config::ConfigOptId { ConfigOptId { id } } -pub fn method MizeResult + Send + Sync + 'static>(name: &str, fun: F) -> ConfigOptId { +pub fn method MizeResult + Send + Sync + 'static>(name: &str, signature: &str, fun: F) -> ConfigOptId { let mize = get_global_mize().unwrap(); let mut cur_part = mize.cur_eval_part.lock().unwrap().clone().unwrap(); let id = cur_part.join(name).unwrap(); // in generate mode: record method metadata, skip normal registration if mize.is_generate_mode().unwrap_or(false) { - mize.record_method(name, id.clone(), "method").ok(); + mize.record_method(name, id.clone(), "method", signature).ok(); return ConfigOptId { id }; } let mut opts = mize.config_opts.lock().unwrap(); @@ -146,7 +146,7 @@ pub fn effect MizeResult + Send + Sync + 'static>(n let id = cur_part.join(name).unwrap(); // in generate mode: record effect metadata, skip normal registration if mize.is_generate_mode().unwrap_or(false) { - mize.record_method(name, id.clone(), "effect").ok(); + mize.record_method(name, id.clone(), "effect", "").ok(); return ConfigOptId { id }; } let mut opts = mize.config_opts.lock().unwrap(); @@ -168,7 +168,7 @@ pub fn thread MizeResult + Send + Sync + 'static>(n let id = cur_part.join(name).unwrap(); // in generate mode: record thread metadata, skip normal registration if mize.is_generate_mode().unwrap_or(false) { - mize.record_method(name, id.clone(), "thread").ok(); + mize.record_method(name, id.clone(), "thread", "").ok(); return ConfigOptId { id }; } let mut opts = mize.config_opts.lock().unwrap(); @@ -199,11 +199,15 @@ pub mod c_api { super::opt(&string) } } - pub extern "C" fn method(name: *const c_char, c_fun: CFun) -> ConfigOptId { + pub extern "C" fn method(name: *const c_char, signature: *const c_char, c_fun: CFun) -> ConfigOptId { unsafe { - let c_str = CStr::from_ptr(name); - let string = c_str.to_string_lossy(); - super::method(&string, move |args| { + let name_str = CStr::from_ptr(name).to_string_lossy(); + let sig_str = if signature.is_null() { + String::new() + } else { + CStr::from_ptr(signature).to_string_lossy().into_owned() + }; + super::method(&name_str, &sig_str, move |args| { let raw_ptr = Box::into_raw(Box::new(args)); let ret_ptr = c_fun(raw_ptr); let data = *Box::from_raw(ret_ptr); diff --git a/core/src/error.rs b/core/src/error.rs index 132a4ce..c5fc21e 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -9,7 +9,7 @@ use std::fmt::Debug; use std::fmt::Display; use std::io; use std::string::FromUtf8Error; -use tracing::{debug, error, info, trace, warn}; +use crate::prelude::*; //use crate::proto::MizeMessage; diff --git a/core/src/instance/mod.rs b/core/src/instance/mod.rs index e0b7567..ec7e440 100644 --- a/core/src/instance/mod.rs +++ b/core/src/instance/mod.rs @@ -9,7 +9,6 @@ use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, Mutex, RwLock}; use std::{thread, vec}; -use tracing::{debug, info, trace}; use crate::set_global_mize; use crate::config::{ConfigOpt, ConfigOptId, MizeFun}; @@ -24,6 +23,7 @@ use crate::memstore::MemStore; use crate::mize_err; use crate::proto::MizeMessage; use crate::error::IntoMizeResult; +use crate::prelude::*; use self::connection::{ConnListener, Connection}; use self::updater::handle_operation; @@ -47,7 +47,7 @@ mod tests; static MSG_CHANNEL_SIZE: usize = 200; -static BUILD_TIME_CONFIG: &str = include_str!(std::env!("MIZE_BUILD_CONFIG")); +static BUILD_TIME_CONFIG: &str = std::env!("MIZE_BUILD_CONFIG"); /// The Instance type is the heart of the mize system #[derive(Clone)] @@ -121,6 +121,35 @@ pub struct MethodMetadata { pub name: String, pub id: MizeId, pub kind: String, // "method", "effect", "thread" + /// Raw signature string, e.g. `"String -> ()"` or `"Command, Func -> ()"`. + pub signature: String, + /// Parsed argument type names (left of `->`). + pub arg_types: Vec, + /// Parsed return type name (right of `->`). Empty means unspecified / ItemData. + pub return_type: String, +} + +/// Parse a method signature like `"String -> ()"` or `"Command, Func -> ()"`. +/// Returns `(arg_types, return_type)` where `return_type` is empty if no `->` was given. +pub fn parse_method_signature(signature: &str) -> (Vec, String) { + let signature = signature.trim(); + if signature.is_empty() { + return (Vec::new(), String::new()); + } + let (args_part, ret_part) = match signature.split_once("->") { + Some((a, r)) => (a.trim(), r.trim().to_string()), + None => (signature, String::new()), + }; + let arg_types = if args_part.is_empty() { + Vec::new() + } else { + args_part + .split(',') + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) + .collect() + }; + (arg_types, ret_part) } #[derive(Clone, Debug)] @@ -129,6 +158,10 @@ pub struct NativeMetadata { pub type_name: String, pub associated: Vec, pub methods: Vec, + /// Signature strings parallel to `associated`. + pub associated_sigs: Vec, + /// Signature strings parallel to `methods`. + pub method_sigs: Vec, } pub struct InstanceRef { @@ -146,8 +179,8 @@ impl PartRef { } impl MizePart for PartRef { - fn id(&self) -> MizeId { - self.id.clone() + fn id(&self) -> MizeResult { + Ok(self.id.clone()) } } @@ -160,11 +193,15 @@ pub struct InstanceAsync { } pub trait MizePart { - fn id(&self) -> MizeId; + fn id(&self) -> MizeResult; } impl Mize { pub fn empty() -> MizeResult { + let runtime = tokio::runtime::Builder::new_multi_thread().enable_all().build()?; + let guard = runtime.enter(); + std::mem::forget(guard); + let id_pool = Arc::new(Mutex::new(VecStringPool::default())); let namespace_pool_raw = StringPool::default(); let connections = Arc::new(Mutex::new(Vec::new())); @@ -206,9 +243,7 @@ impl Mize { part_metadata: Arc::new(Mutex::new(HashMap::new())), #[cfg(feature = "async")] - runtime: Arc::new(Mutex::new( - Runtime::new().mres_msg("Could not create async runtime")?, - )), + runtime: Arc::new(Mutex::new(runtime)), }; #[cfg(feature = "target-os")] @@ -244,7 +279,7 @@ impl Mize { console_log!("before loading build time config"); // load the config from build time - let config = ItemData::from_toml(BUILD_TIME_CONFIG)?; + let config = ItemData::from_json(BUILD_TIME_CONFIG.to_owned())?; instance.set_blocking("0", config); #[cfg(feature = "target-wasm ")] @@ -546,7 +581,7 @@ impl Mize { } /// Record a method/effect/thread declaration while in generate mode. - pub fn record_method(&self, name: &str, id: MizeId, kind: &str) -> MizeResult<()> { + pub fn record_method(&self, name: &str, id: MizeId, kind: &str, signature: &str) -> MizeResult<()> { let cur_part = self.cur_eval_part.lock()?.clone() .ok_or_else(|| mize_err!("no cur_eval_part set"))?; let mut metadata_map = self.part_metadata.lock()?; @@ -554,10 +589,14 @@ impl Mize { part_name: cur_part.dot(), ..Default::default() }); + let (arg_types, return_type) = parse_method_signature(signature); let m = MethodMetadata { name: name.to_string(), id, kind: kind.to_string(), + signature: signature.to_string(), + arg_types, + return_type, }; match kind { "effect" => metadata.effects.push(m), @@ -568,7 +607,15 @@ impl Mize { } /// Record a native type inclusion while in generate mode. - pub fn record_native(&self, name: &str, type_name: &str, associated: Vec, methods: Vec) -> MizeResult<()> { + pub fn record_native( + &self, + name: &str, + type_name: &str, + associated: Vec, + methods: Vec, + associated_sigs: Vec, + method_sigs: Vec, + ) -> MizeResult<()> { let cur_part = self.cur_eval_part.lock()?.clone() .ok_or_else(|| mize_err!("no cur_eval_part set"))?; let mut metadata_map = self.part_metadata.lock()?; @@ -581,6 +628,8 @@ impl Mize { type_name: type_name.to_string(), associated, methods, + associated_sigs, + method_sigs, }); Ok(()) } @@ -805,12 +854,15 @@ impl Mize { ) -> MizeResult<()> { let mut threads_inner = self.threads.lock()?; let mut next_thread_id = self.next_thread_id.lock()?; + let tokio_handle = tokio::runtime::Handle::current(); let my_thread_id_no_mutex_guard = *next_thread_id; let _thread_mutex = self.threads.clone(); let name_to_move = name.to_owned(); let to_spawn = move || -> () { debug!("spawning thread: {}", name_to_move); + let guard = tokio_handle.enter(); + std::mem::forget(guard); let _my_thread_id = my_thread_id_no_mutex_guard; let res = func(); @@ -883,8 +935,8 @@ impl Mize { let mut next_thread_id = self.next_thread_id.lock()?; threads_inner.push((*next_thread_id, name.to_owned(), None)); - let runtime_inner = self.runtime.lock().unwrap(); - runtime_inner.spawn(func); + let runtime = tokio::runtime::Handle::current(); + runtime.spawn(func); *next_thread_id += 1; @@ -893,9 +945,7 @@ impl Mize { #[cfg(feature = "async")] pub fn async_get_handle(&self) -> Handle { - let runtime_inner = self.runtime.lock().unwrap(); - let handle = runtime_inner.handle().to_owned(); - handle + tokio::runtime::Handle::current() } #[cfg(feature = "async")] @@ -916,16 +966,13 @@ impl Mize { .expect("mutex lock failed in spawn_async_blocking"); threads_inner.push((*next_thread_id, name.to_owned(), None)); - let runtime_inner = self.runtime.lock().unwrap(); - let handle = runtime_inner.handle().to_owned(); + let runtime = tokio::runtime::Handle::current(); *next_thread_id += 1; - drop(runtime_inner); drop(threads_inner); drop(next_thread_id); - handle.enter(); - let result = handle.block_on(func); + let result = runtime.block_on(func); return result; } @@ -958,24 +1005,29 @@ impl Mize { let mut opt = config_opts .get_mut(&id) - .ok_or_else(|| mize_err!("Config opt for {name} not in config_opts"))?; + .ok_or_else(|| mize_err!("Config opt for {id} not in config_opts"))?; if let Some(val) = opt.val.clone() { return Ok(val); } // in case it is not cached run the fun if it exists - if let Some(fun) = &opt.fun { + if opt.fun.is_some() { + let fun = opt.fun.take().unwrap(); + drop(config_opts); let res = fun()?; + let mut config_opts = self.config_opts.lock().unwrap(); + let mut opt = config_opts.get_mut(&id).unwrap(); + opt.fun = Some(fun); opt.val = Some(res.clone()); return Ok(res); } - Err(mize_err!("ConfigOpt {name} has no fun and no cached value")) + Err(mize_err!("ConfigOpt {id} has no fun and no cached value")) } pub fn dyn_call(&mut self, part_id: MizeId, method: &str, args: ItemData) -> MizeResult { - debug!("dyn call {}.{} with args: {}", part_id, method, args); + debug!("dyn call {}/{} with args: {}", part_id, method, args); let mut fun_values = self.fun_values.lock()?; let id = part_id.clone().join(method)?; @@ -985,7 +1037,9 @@ impl Mize { let calling_part = self.clone().cur_eval_part()?; self.clone().set_cur_eval_part(Some(part_id)); + println!("before call"); let res = fun(args); + println!("after call"); self.clone().set_cur_eval_part(calling_part); let mut fun_values = self.fun_values.lock()?; fun_values.insert(id, fun); diff --git a/core/src/instance/subscription.rs b/core/src/instance/subscription.rs index ddb7577..36b43f7 100644 --- a/core/src/instance/subscription.rs +++ b/core/src/instance/subscription.rs @@ -2,13 +2,13 @@ use core::fmt; use flume::Sender; use std::rc::Rc; use std::sync::Arc; -use tracing::trace; use crate::error::MizeResult; use crate::id::MizeId; use crate::instance::connection::Connection; use crate::item::Item; use crate::proto::MizeMessage; +use crate::prelude::*; use super::Mize; diff --git a/core/src/instance/updater.rs b/core/src/instance/updater.rs index 64e08ee..49c4919 100644 --- a/core/src/instance/updater.rs +++ b/core/src/instance/updater.rs @@ -1,11 +1,11 @@ use flume::Receiver; use std::borrow::BorrowMut; use std::sync::Arc; -use tracing::{error, trace, warn}; use crate::error::{MizeError, MizeResult, MizeResultTrait}; use crate::id::MizeId; use crate::mize_err; +use crate::prelude::*; use crate::proto::{MessageCmd, MizeMessage}; use crate::{instance::Mize, item::ItemData}; diff --git a/core/src/item.rs b/core/src/item.rs index 12dfa35..18cc830 100644 --- a/core/src/item.rs +++ b/core/src/item.rs @@ -1,8 +1,9 @@ use crate::{config, get_global_mize}; use crate::config::{ConfigOpt, FromItemData, MizeFun}; use ciborium::into_writer; +use ciborium::from_reader; use colored::Colorize; -use serde_json::from_reader; +use serde::de::DeserializeOwned; use core::fmt; use serde::Deserialize; use serde::Serialize; @@ -13,7 +14,8 @@ use std::sync::MutexGuard; use std::{boxed, io}; use std::fmt::Display; use std::i128; -use tracing::{debug, instrument, trace, warn}; +use crate::tracing::instrument; +use crate::prelude::*; use crate::error::{IntoMizeResult, MizeError, MizeErrorWhichImplementsError, MizeResult}; use crate::id::MizeId; @@ -256,7 +258,12 @@ impl ItemData { let fun_num = self.get_path("_fun_num")?.value_u32()?; let fun_id = mize.clone().id_new_dots("mize.fun")?.join(format!("{fun_num}").as_str())?; let fun = fun_values.remove(&fun_id).ok_or(mize_err!("fun with id {fun_id} not in fun_values"))?; + + drop(fun_values); let res = fun(args)?; + let mut fun_values = mize.fun_values.lock()?; + fun_values.insert(fun_id, fun); + return Ok(res); } @@ -406,6 +413,13 @@ impl ItemData { return None; } + pub fn deserialize(&self) -> MizeResult { + let mut buffer = Vec::new(); + into_writer(&self, &mut buffer)?; + let cbor_val: T = from_reader(buffer.as_slice())?; + Ok(cbor_val) + } + /// Get an immutable reference to the native value stored in this ItemData. /// /// If the ItemData has a `_native` field (stored via `from_native()`), returns a guard @@ -467,6 +481,7 @@ impl ItemData { /// /// Otherwise, constructs the value via `T::from_itemdata(self)`, stores it in the /// registry, and returns a guard to it. + /// i hate rust. (as you can't have a generic FromItemData impl and then more specific ones.) pub fn native_from(&self) -> MizeResult> { // Fast path: the registry already holds a T for this ItemData if let Some(id) = self.try_get_native_id() { diff --git a/core/src/lib.rs b/core/src/lib.rs index cacbc57..0bee2c8 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -9,7 +9,7 @@ use std::fmt::format; macro_rules! out { ($($arg:tt)*) => { // format_args! handles string interpolation safely at compile time - if let Err(e) = $crate::write_to_mize_stdout(format_args!($($arg)*)) { + if let Err(e) = $crate::write_to_mize_stdout(format_args!("{}\n", format_args!($($arg)*))) { // Choose your error handling behavior here (panic, print to stderr, or ignore) eprintln!("out! macro failed to write!!"); } @@ -17,7 +17,7 @@ macro_rules! out { } pub fn write_to_mize_stdout(args: std::fmt::Arguments) -> MizeResult<()> { - println!("{}", args); + print!("{}", args); Ok(()) } @@ -84,8 +84,11 @@ pub mod prelude { pub use config::*; pub use api::*; pub use mize_macros::*; + pub use crate::tracing::{trace, warn, debug, info, error}; } pub use flume; +use tokio::runtime::Builder; +use tokio::runtime::Runtime; pub use tracing; @@ -108,13 +111,15 @@ pub use error::MizeError; pub use error::MizeResult; pub use instance::Mize; pub use instance::{ - MizePart, PartMetadata, OptMetadata, MethodMetadata, NativeMetadata, + MizePart, PartMetadata, OptMetadata, MethodMetadata, NativeMetadata, parse_method_signature, }; pub use mize_macros::*; use std::path::PathBuf; use std::sync::{Arc, Mutex, OnceLock}; +use crate::platform::os; + /// Global Mize instance storage. /// This is set once when the Mize instance is created and can be accessed from anywhere. pub static GLOBAL_MIZE: OnceLock>> = OnceLock::new(); @@ -144,9 +149,32 @@ pub fn set_global_mize(mize: Mize) -> MizeResult<()> { /// C API function to set the global Mize instance from a dynamically loaded part. /// This is a hack to allow Rust parts loaded as .so files to access the global Mize instance. +// i hate rust. #[unsafe(no_mangle)] -pub extern "C" fn mize_rust_hack_set_global(mize: Arc>) { +pub extern "C" fn mize_rust_hack_set_global(mize: Arc>, dispatch_ptr: *const std::ffi::c_void) { + // and also set the tokio runtime + //let mize_locked = mize.lock().unwrap(); + //let rt = mize_locked.runtime.lock().unwrap(); + //rt.enter(); + //drop(rt); + //drop(mize_locked); + let rt = Builder::new_multi_thread().enable_all().build().unwrap(); + let guard = rt.enter(); + std::mem::forget(guard); + + use crate::tracing::Dispatch; let _ = GLOBAL_MIZE.set(mize); + + //and also init tracing + unsafe { + /// i hate rust. + let dispatch = &*(dispatch_ptr as *const Dispatch); + if let Err(e) = tracing::dispatcher::set_global_default(dispatch.clone()) { + println!("failed to set tracing dispatcher: {e}"); + } + tracing::callsite::rebuild_interest_cache(); + } + } /// Resolve an executable name to its full path in the nixpkgs store. diff --git a/core/src/memstore.rs b/core/src/memstore.rs index 9cdc7e7..e73dcbf 100644 --- a/core/src/memstore.rs +++ b/core/src/memstore.rs @@ -4,7 +4,7 @@ use std::collections::binary_heap::Iter; use std::collections::HashMap; use std::iter::Map; use std::sync::{Arc, Mutex}; -use tracing::{instrument, trace}; +use crate::tracing::instrument; use crate::error::{IntoMizeResult, MizeError, MizeResult}; use crate::id::MizeId; @@ -13,6 +13,7 @@ use crate::instance::Mize; use crate::item::get_raw_from_cbor; use crate::item::{Item, ItemData}; use crate::mize_err; +use crate::prelude::*; #[derive(Clone, Debug)] pub struct MemStore { diff --git a/core/src/platform/os/fsstore.rs b/core/src/platform/os/fsstore.rs index b852a86..2f074de 100644 --- a/core/src/platform/os/fsstore.rs +++ b/core/src/platform/os/fsstore.rs @@ -4,7 +4,6 @@ use std::fs::OpenOptions; use std::io::Write; use std::path::{Path, PathBuf}; use sysinfo::{Pid, ProcessRefreshKind, RefreshKind, System}; -use tracing::debug; use crate::id::MizeId; use crate::item::{Item, ItemData}; @@ -15,6 +14,9 @@ use crate::item::get_raw_from_cbor; use crate::item::IntoItemData; use crate::memstore::MemStore; use crate::{instance::store::Store, mize_err}; +use crate::prelude::*; + +#[cfg(target_family = "unix")] use tokio::net::UnixStream; #[derive(Clone, Debug)] @@ -72,6 +74,7 @@ impl FileStore { } } +#[cfg(target_family = "unix")] async fn try_connect_to_sock(store_path: String) -> MizeResult<()> { match UnixStream::connect(PathBuf::from(store_path).join("sock")).await { Err(_) => Err(mize_err!("")), @@ -79,6 +82,21 @@ async fn try_connect_to_sock(store_path: String) -> MizeResult<()> { } } +#[cfg(target_family = "windows")] +async fn try_connect_to_sock(store_path: String) -> MizeResult<()> { + use tokio::net::windows::named_pipe::{ClientOptions}; + let pipe_name = format!( + "\\.\\pipe\\mize_{}", + store_path.replace('\\', "_").replace('/', "_").replace(':', "_") + ); + // ClientOptions::new().open() is synchronous, not async + // So we just try to open and immediately close it + match ClientOptions::new().open(&pipe_name) { + Err(_) => Err(mize_err!("")), + Ok(_) => Ok(()), + } +} + impl Store for FileStore { fn new_id(&self) -> MizeResult { let mut next_id: u64 = @@ -191,6 +209,7 @@ impl Store for FileStore { } } +#[cfg(target_family = "unix")] fn valid_pid_file(path: &Path) -> MizeResult> { let pid_file_path = path.join("pid"); diff --git a/core/src/platform/os/logging.rs b/core/src/platform/os/logging.rs index 9609889..f2252bd 100644 --- a/core/src/platform/os/logging.rs +++ b/core/src/platform/os/logging.rs @@ -12,8 +12,7 @@ use std::sync::Arc; use std::sync::Mutex; use tokio::sync::mpsc; use tracing::level_filters::LevelFilter; -use tracing::Event; -use tracing::{debug, error, info, trace, warn}; +use tracing::{Dispatch, Event}; use tracing::{field::Visit, Id, Subscriber}; use tracing::{span_enabled, Instrument, Level}; use tracing_core::Field; @@ -29,10 +28,65 @@ use crate::id::MizeId; use crate::item::ItemData; use crate::MizeError; use crate::MizeResult; +use crate::prelude::*; static DEFAULT_LOG_LEVEL: LevelFilter = LevelFilter::WARN; -pub fn init_logger(cli_matches: &ArgMatches) { + +/* +#[macro_export] +macro_rules! trace { + ($($arg:tt)*) => { + // format_args! handles string interpolation safely at compile time + if let Err(e) = $crate::write_to_mize_stdout(format_args!("[ {} ] {}\n", colored::Colorize::yellow("TRACE"), format_args!($($arg)*))) { + // Choose your error handling behavior here (panic, print to stderr, or ignore) + eprintln!("out! macro failed to write!!"); + } + }; +} +#[macro_export] +macro_rules! debug { + ($($arg:tt)*) => { + // format_args! handles string interpolation safely at compile time + if let Err(e) = $crate::write_to_mize_stdout(format_args!("[ {} ] {}\n", colored::Colorize::green("DEBUG"), format_args!($($arg)*))) { + // Choose your error handling behavior here (panic, print to stderr, or ignore) + eprintln!("out! macro failed to write!!"); + } + }; +} +#[macro_export] +macro_rules! info { + ($($arg:tt)*) => { + // format_args! handles string interpolation safely at compile time + if let Err(e) = $crate::write_to_mize_stdout(format_args!("[ {} ] {}\n", colored::Colorize::blue("INFO"), format_args!($($arg)*))) { + // Choose your error handling behavior here (panic, print to stderr, or ignore) + eprintln!("out! macro failed to write!!"); + } + }; +} +#[macro_export] +macro_rules! warn { + ($($arg:tt)*) => { + // format_args! handles string interpolation safely at compile time + if let Err(e) = $crate::write_to_mize_stdout(format_args!("[ {} ] {}\n", colored::Colorize::truecolor("WARN", 245, 164, 66), format_args!($($arg)*))) { + // Choose your error handling behavior here (panic, print to stderr, or ignore) + eprintln!("out! macro failed to write!!"); + } + }; +} +#[macro_export] +macro_rules! error { + ($($arg:tt)*) => { + // format_args! handles string interpolation safely at compile time + if let Err(e) = $crate::write_to_mize_stdout(format_args!("[ {} ] {}\n", colored::Colorize::red("ERROR"), format_args!($($arg)*))) { + // Choose your error handling behavior here (panic, print to stderr, or ignore) + eprintln!("out! macro failed to write!!"); + } + }; +} + */ + +pub fn init_logger(cli_matches: Option<&ArgMatches>) { trace!("init_logger called"); // to save log messages, before the logger is setup let mut log_messages: Vec<(Level, String)> = Vec::new(); @@ -96,67 +150,69 @@ pub fn init_logger(cli_matches: &ArgMatches) { log_messages.append(&mut val_mize_log.1); // check -vvvvv flags - let v_flag_count = cli_matches.get_count("verbose"); - if v_flag_count > 0 { - let default_log_level_as_num = match DEFAULT_LOG_LEVEL { - LevelFilter::OFF => 0, - LevelFilter::ERROR => 1, - LevelFilter::WARN => 2, - LevelFilter::INFO => 3, - LevelFilter::DEBUG => 4, - LevelFilter::TRACE => 5, - }; - let new_log_level_num = default_log_level_as_num + v_flag_count; - log_level = match new_log_level_num { - 0 => LevelFilter::OFF, - 1 => LevelFilter::ERROR, - 2 => LevelFilter::WARN, - 3 => LevelFilter::INFO, - 4 => LevelFilter::DEBUG, - 5 => LevelFilter::TRACE, - _ => { - log_messages.push(( - Level::TRACE, - format!( - "the number of verbose (-v) flags passed ({}) exeeds the maximumg log_level", - v_flag_count - ), - )); - LevelFilter::TRACE - } - }; - log_messages.push(( - Level::TRACE, - format!("set log level from the verbose flags to {}", log_level), - )); - } + if let Some(cli_matches) = cli_matches { + let v_flag_count = cli_matches.get_count("verbose"); + if v_flag_count > 0 { + let default_log_level_as_num = match DEFAULT_LOG_LEVEL { + LevelFilter::OFF => 0, + LevelFilter::ERROR => 1, + LevelFilter::WARN => 2, + LevelFilter::INFO => 3, + LevelFilter::DEBUG => 4, + LevelFilter::TRACE => 5, + }; + let new_log_level_num = default_log_level_as_num + v_flag_count; + log_level = match new_log_level_num { + 0 => LevelFilter::OFF, + 1 => LevelFilter::ERROR, + 2 => LevelFilter::WARN, + 3 => LevelFilter::INFO, + 4 => LevelFilter::DEBUG, + 5 => LevelFilter::TRACE, + _ => { + log_messages.push(( + Level::TRACE, + format!( + "the number of verbose (-v) flags passed ({}) exeeds the maximumg log_level", + v_flag_count + ), + )); + LevelFilter::TRACE + } + }; + log_messages.push(( + Level::TRACE, + format!("set log level from the verbose flags to {}", log_level), + )); + } - // check --log-level arg - if let Some(log_level_arg_string) = cli_matches.get_one::("log-level") { - let log_level_from_arg = match log_level_arg_string.to_owned().to_lowercase().as_str() { - "none" => LevelFilter::OFF, - "trace" => LevelFilter::TRACE, - "debug" => LevelFilter::DEBUG, - "info" => LevelFilter::INFO, - "warn" => LevelFilter::WARN, - "error" => LevelFilter::ERROR, - _ => { - log_messages.push((Level::WARN, format!( - "The argument to --log-level \"{}\" is not a valid log-level. loglevel stays at: {}" - , log_level_arg_string - , log_level - ))); - log_level - } - }; - log_level = log_level_from_arg; - log_messages.push(( - Level::TRACE, - format!( - "set log level from the --log-level arg to {}", - log_level_from_arg - ), - )); + // check --log-level arg + if let Some(log_level_arg_string) = cli_matches.get_one::("log-level") { + let log_level_from_arg = match log_level_arg_string.to_owned().to_lowercase().as_str() { + "none" => LevelFilter::OFF, + "trace" => LevelFilter::TRACE, + "debug" => LevelFilter::DEBUG, + "info" => LevelFilter::INFO, + "warn" => LevelFilter::WARN, + "error" => LevelFilter::ERROR, + _ => { + log_messages.push((Level::WARN, format!( + "The argument to --log-level \"{}\" is not a valid log-level. loglevel stays at: {}" + , log_level_arg_string + , log_level + ))); + log_level + } + }; + log_level = log_level_from_arg; + log_messages.push(( + Level::TRACE, + format!( + "set log level from the --log-level arg to {}", + log_level_from_arg + ), + )); + } } // actually set the log_level on the builder @@ -181,13 +237,18 @@ pub fn init_logger(cli_matches: &ArgMatches) { } Ok(()) }); - builder + let subscriber = builder //.with_env_filter(my_env_filter) .without_time() .event_format(MyFormatter) .fmt_fields(field_formatter) .with_max_level(log_level) - .init(); + .finish(); + + let dispatch = Dispatch::new(subscriber); + if let Err(e) = tracing::dispatcher::set_global_default(dispatch) { + println!("faild to set_global_default(dispatch): {e}"); + } // write out all log messages from log_messages for (level, msg) in log_messages { diff --git a/core/src/platform/os/mod.rs b/core/src/platform/os/mod.rs index df6388f..bbe2c1a 100644 --- a/core/src/platform/os/mod.rs +++ b/core/src/platform/os/mod.rs @@ -1,5 +1,6 @@ use clap::ArgMatches; use colored::Colorize; +use tracing::Dispatch; use core::fmt; use flate2::bufread::GzDecoder; use sha2::{Digest, Sha256}; @@ -12,7 +13,6 @@ use std::path::PathBuf; use std::time::UNIX_EPOCH; use tar::Archive; use tracing::Event; -use tracing::{debug, info, trace, warn}; use tracing::field::Visit; use tracing::Level; use tracing_core::Field; @@ -25,12 +25,8 @@ use tracing_subscriber::registry::LookupSpan; use std::sync::Arc; use std::sync::Mutex; -use crate::GLOBAL_MIZE; -use crate::config::ConfigOpt; -use crate::error::{IntoMizeResult, MizeResult}; -use crate::instance::Mize; -use crate::item::{data_from_string, IntoItemData, ItemData}; -use crate::mize_err; +use crate::prelude::*; +use crate::item::data_from_string; use self::fsstore::FileStore; @@ -40,8 +36,14 @@ pub mod logging; #[cfg(target_family = "unix")] mod unix_socket; +#[cfg(target_family = "windows")] +mod windows_socket; + #[cfg(target_family = "unix")] use crate::platform::os::unix_socket::UnixListener; + +#[cfg(target_family = "windows")] +use crate::platform::os::windows_socket::WindowsListener as UnixListener; //mod web; pub fn os_instance_init(mize: &mut Mize) -> MizeResult<()> { @@ -133,7 +135,10 @@ pub fn os_instance_init(mize: &mut Mize) -> MizeResult<()> { #[cfg(target_family = "windows")] { - error!("CONNECTING... would connect, but that is not implemented on windows yet"); + info!("CONNECTING"); + use crate::platform::os::windows_socket; + windows_socket::connect(mize, store_path.into())?; + return Ok(()); } } else { // else open it ourselves @@ -149,7 +154,7 @@ pub fn os_instance_init(mize: &mut Mize) -> MizeResult<()> { #[cfg(target_family = "windows")] { - warn!("would add a Listener on a local socket, but that is not yet implemented for windows"); + mize.add_conn_listener(UnixListener::new(path)?)?; } } @@ -273,31 +278,33 @@ pub fn fetch_part(mize: &mut Mize, part_name: &str) -> MizeResult { fn get_part_path(mize: &mut Mize, part_name: &str, _path: Option) -> MizeResult { + let part_symbol_name = part_name.replace(".", "_"); + // check if $name.src is set if let Ok(itm) = mize.get_config(format!("{part_name}.src").as_str()) { let part_src = itm.value_string().map_err(|e| e.msg(format!("opt {part_name}.src was not a string")))?; // will only work for rust for now - let part_path = format!("{part_src}/target/debug/libmize_part_{part_name}.so"); + let part_path = format!("{part_src}/target/debug/libmize_part_{part_symbol_name}.so"); return Ok(part_path); } // check if $name.out is set if let Ok(itm) = mize.get_config(format!("{part_name}.out").as_str()) { let part_out = itm.value_string().map_err(|e| e.msg(format!("opt {part_name}.out was not a string")))?; - let part_path = format!("{part_out}/lib/libmize_part_{part_name}.so"); + let part_path = format!("{part_out}/lib/libmize_part_{part_symbol_name}.so"); return Ok(part_path); } // check if we find the part inside mize.src if let Ok(itm) = mize.get_config("mize.src") { let mize_src = itm.value_string().map_err(|e| e.msg("opt mize.src was not a string"))?; - let part_path = format!("{mize_src}/target/debug/libmize_part_{part_name}.so"); + let part_path = format!("{mize_src}/target/debug/libmize_part_{part_symbol_name}.so"); return Ok(part_path); } // fetch the part from https://mize.works let out_path = fetch_part(mize, part_name)?; - return Ok(format!("{out_path}/lib/libmize_part_{part_name}.so")); + return Ok(format!("{out_path}/lib/libmize_part_{part_symbol_name}.so")); //Err(mize_err!("part {part_name} not found")) } @@ -308,16 +315,33 @@ pub fn load_part(mize: &mut Mize, part_name: &str, path: Option) -> Mize let lib = unsafe { libloading::Library::new(part_path)? }; unsafe { - if let Ok(rust_hack_func) = lib.get::>)>>("mize_rust_hack_set_global".as_bytes()) { - rust_hack_func(GLOBAL_MIZE.get().unwrap().clone()) + if let Ok(rust_hack_func) = lib.get::>, *const std::ffi::c_void)>>("mize_rust_hack_set_global".as_bytes()) { + + tracing::dispatcher::get_default(|dispatch| { + rust_hack_func(GLOBAL_MIZE.get().unwrap().clone(), dispatch as *const Dispatch as *const std::ffi::c_void); + }); + }; } + let part_symbol_name = part_name.replace(".", "_"); + let func: libloading::Symbol< unsafe extern "C" fn() -> MizeResult<()>, - > = unsafe { lib.get(format!("part_{}", part_name).as_bytes())? }; + > = unsafe { lib.get(format!("part_{}", part_symbol_name).as_bytes())? }; - mize.clone().set_cur_eval_part(Some(mize.clone().id_new_dots(part_name)?))?; + let part_id = mize.clone().id_new_dots(part_name)?; + { + let mut opts = mize.config_opts.lock()?; + opts.entry(part_id.clone()).or_insert_with(|| ConfigOpt { + name: part_name.to_owned(), + val: Some(ItemData::new()), + fun: None, + deps: Vec::new(), + }); + } + + mize.clone().set_cur_eval_part(Some(part_id))?; unsafe { func()? }; mize.clone().set_cur_eval_part(None)?; diff --git a/core/src/platform/os/unix_socket.rs b/core/src/platform/os/unix_socket.rs index 03d264a..36d268d 100644 --- a/core/src/platform/os/unix_socket.rs +++ b/core/src/platform/os/unix_socket.rs @@ -5,12 +5,12 @@ use std::path::{Path, PathBuf}; use tokio::io::{AsyncReadExt, AsyncWriteExt, Interest}; use tokio::net::unix::{OwnedReadHalf, OwnedWriteHalf}; use tokio::net::{UnixListener as TokioUnixListener, UnixStream}; -use tracing::{debug, info, warn}; use crate::error::{IntoMizeResult, MizeError, MizeResult}; use crate::instance::connection::{ConnListener, Connection}; use crate::instance::{self, Mize}; use crate::proto::{self, MizeMessage}; +use crate::prelude::*; pub struct UnixListener { sock_path: PathBuf, diff --git a/core/src/platform/os/windows_socket.rs b/core/src/platform/os/windows_socket.rs new file mode 100644 index 0000000..5d90d72 --- /dev/null +++ b/core/src/platform/os/windows_socket.rs @@ -0,0 +1,224 @@ +// This module is only compiled on Windows +// It provides the same functionality as unix_socket.rs but using Windows named pipes + +use ciborium::Value as CborValue; +use flume::{unbounded, Receiver, Sender}; +use std::path::PathBuf; +use std::sync::Arc; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::windows::named_pipe::{ClientOptions, ServerOptions}; +use tokio::sync::Mutex; +use tracing::{debug, info, warn}; + +use crate::error::{IntoMizeResult, MizeError, MizeResult}; +use crate::instance::connection::{ConnListener, Connection}; +use crate::instance::{self, Mize}; +use crate::proto::{self, MizeMessage}; + +pub struct WindowsListener { + pipe_name: String, +} + +impl WindowsListener { + pub fn new(store_path: PathBuf) -> MizeResult { + // On Windows, we use a named pipe with a specific format + // The format is \.\pipe\ for local pipes + // We'll use the store path hash or name to create a unique pipe name + let pipe_name = format!( + "\\.\\pipe\\mize_{}", + store_path.to_string_lossy().replace('\\', "_").replace('/', "_").replace(':', "_") + ); + Ok(WindowsListener { pipe_name }) + } +} + +pub fn connect(instance: &mut Mize, store_path: PathBuf) -> MizeResult<()> { + let conn_id = instance.spawn_async_blocking( + "windows_connection", + connect_async(instance.clone(), store_path), + )?; + + let ns_of_peer_str = instance + .get(format!( + "inst/con_by_id/{}/peer/self/config/namespace", + conn_id + ))? + .value_string()?; + let ns_of_peer = instance.namespace_from_string(ns_of_peer_str)?; + + info!( + "connect_async ... ns_of_peer: {}", + ns_of_peer.clone().as_string() + ); + + instance.connection_set_namespace(conn_id, ns_of_peer.clone()); + instance.set_namespace(ns_of_peer); + + Ok(()) +} + +async fn connect_async(mut instance: Mize, store_path: PathBuf) -> MizeResult { + let pipe_name = format!( + "\\.\\pipe\\mize_{}", + store_path.to_string_lossy().replace('\\', "_").replace('/', "_").replace(':', "_") + ); + + // Create the client synchronously + let client = ClientOptions::new().open(&pipe_name)?; + + // Wrap the client in an Arc so it can be shared between incoming and outgoing tasks + let shared_client = Arc::new(Mutex::new(client)); + + let (send_tx, send_rx) = unbounded::(); + + let conn_id = instance.new_connection(send_tx)?; + + let cloned_instance = instance.clone(); + let incoming_client = shared_client.clone(); + instance.spawn_background("incomming", move || { + let result = windows_incomming(incoming_client, cloned_instance, conn_id); + if let Err(err) = result { + warn!("Connection closing because of EOF: {:?}", err); + } + Ok(()) + }); + + let outgoing_cloned_instance = instance.clone(); + let outgoing_client = shared_client.clone(); + instance.spawn_background("outgoing", move || { + let result = windows_outgoing(outgoing_client, send_rx, outgoing_cloned_instance, conn_id); + if let Err(err) = result { + warn!("Connection closing because of EOF: {:?}", err); + } + Ok(()) + }); + + Ok(conn_id) +} + +impl ConnListener for WindowsListener { + fn listen(self, mut instance: Mize) -> MizeResult<()> { + instance.spawn_async("windows listen async", windows_listen(self, instance.clone())); + Ok(()) + } +} + +async fn windows_listen(listener: WindowsListener, mut instance: Mize) -> MizeResult<()> { + // Create the first server instance + let mut server = ServerOptions::new() + .first_pipe_instance(true) + .create(&listener.pipe_name)?; + + loop { + // Wait for a client to connect + server.connect().await.mres_msg("Error while accepting Windows named pipe connection")?; + info!("new connection"); + + let (send_tx, send_rx) = unbounded::(); + let conn_id = instance.new_connection(send_tx)?; + + // Take ownership of the current server (which is now connected) + let connected_server = server; + + // Create a new server for the next connection + server = ServerOptions::new().create(&listener.pipe_name)?; + + // Wrap the connected server in an Arc so it can be shared + let shared_server = Arc::new(Mutex::new(connected_server)); + + let cloned_instance = instance.clone(); + let incoming_server = shared_server.clone(); + instance.spawn_background("incomming", move || { + let result = windows_incomming(incoming_server, cloned_instance, conn_id); + if let Err(err) = result { + warn!("Connection closing because of EOF: {:?}", err); + } + Ok(()) + }); + + let outgoing_cloned_instance = instance.clone(); + let outgoing_server = shared_server.clone(); + instance.spawn_background("outgoing", move || { + let result = windows_outgoing(outgoing_server, send_rx, outgoing_cloned_instance, conn_id); + if let Err(err) = result { + warn!("Connection closing because of EOF: {:?}", err); + } + Ok(()) + }); + } +} + +fn windows_outgoing(shared_pipe: Arc>, send_rx: Receiver, mut instance: Mize, conn_id: u64) -> MizeResult<()> +where + W: AsyncWriteExt + Unpin, +{ + for msg in send_rx { + debug!("windows outgoing got msg: {}", msg); + let adapter = MyCiboriumWriter { + inner: &mut *shared_pipe.blocking_lock(), + instance: &mut instance, + }; + let value = msg.value(); + ciborium::into_writer(&value, adapter)? + } + Ok(()) +} + +pub fn windows_incomming(shared_pipe: Arc>, mut instance: Mize, conn_id: u64) -> MizeResult<()> +where + R: AsyncReadExt + Unpin, +{ + loop { + let adapter = MyCiboriumReader { + inner: &mut *shared_pipe.blocking_lock(), + instance: &mut instance, + }; + let value: CborValue = ciborium::from_reader(adapter)?; + if let CborValue::Integer(_) = value { + break; + } + let msg = MizeMessage::new(value, conn_id); + debug!("windows incomming got msg: {}", msg); + instance.got_msg(msg); + } + Ok(()) +} + +struct MyCiboriumWriter<'a, W> { + inner: &'a mut W, + instance: &'a mut Mize, +} + +impl<'a, W> ciborium_io::Write for MyCiboriumWriter<'a, W> +where + W: AsyncWriteExt + Unpin, +{ + type Error = MizeError; + fn write_all(&mut self, data: &[u8]) -> Result<(), Self::Error> { + let runtime = self.instance.runtime.lock()?; + let _ = runtime.block_on(self.inner.write_all(data))?; + Ok(()) + } + fn flush(&mut self) -> Result<(), Self::Error> { + let handle = self.instance.async_get_handle(); + let _ = handle.block_on(self.inner.flush()); + Ok(()) + } +} + +struct MyCiboriumReader<'a, R> { + inner: &'a mut R, + instance: &'a mut Mize, +} + +impl<'a, R> ciborium_io::Read for MyCiboriumReader<'a, R> +where + R: AsyncReadExt + Unpin, +{ + type Error = MizeError; + fn read_exact(&mut self, data: &mut [u8]) -> Result<(), Self::Error> { + let handle = self.instance.async_get_handle(); + let _ = handle.block_on(self.inner.read_exact(data))?; + Ok(()) + } +} diff --git a/flake.nix b/flake.nix index 648c57c..c2ba2b9 100644 --- a/flake.nix +++ b/flake.nix @@ -34,10 +34,8 @@ let # mize build time config mizeBuildConfig = { - config = { - namespace = "mize.buildtime.ns"; - module_url = "parts.mize.works"; - }; + namespace = "mize.buildtime.ns"; + module_url = "parts.mize.works"; }; @@ -161,11 +159,7 @@ in { # shell without spacetime and other dev commands. just all needed to build mize or ppc buildShell = pkgs.mkShell { - MIZE_BUILD_CONFIG = let - settingsFormat = pkgs.formats.toml { }; - in settingsFormat.generate "mize-build-config.toml" { - config = mizeBuildConfig; - }; + MIZE_BUILD_CONFIG = builtins.toJSON mizeBuildConfig; shellHook = '' mize_project_root=$(${pkgs.lib.getExe pkgs.git} rev-parse --show-toplevel) export MIZE_CONFIG_FILES=$mize_project_root/mize_config.toml @@ -234,11 +228,7 @@ in { }; default = pkgs.mkShell rec { - MIZE_BUILD_CONFIG = let - settingsFormat = pkgs.formats.toml { }; - in settingsFormat.generate "mize-build-config.toml" { - config = mizeBuildConfig; - }; + MIZE_BUILD_CONFIG = builtins.toJSON mizeBuildConfig; shellHook = '' mize_project_root=$(${pkgs.lib.getExe pkgs.git} rev-parse --show-toplevel) ''; diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 0bfb552..cb3422b 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -227,19 +227,45 @@ fn generate_arg_passing(args: &[(Ident, Type)]) -> Vec }).collect() } +/// Last path segment of a Type, for signature strings (e.g. `clap::Command` -> `Command`). +fn type_to_sig_name(ty: &Type) -> String { + match ty { + Type::Path(p) => p + .path + .segments + .last() + .map(|s| s.ident.to_string()) + .unwrap_or_else(|| quote!(#ty).to_string()), + _ => quote!(#ty).to_string().replace(' ', ""), + } +} + +/// Build a signature string like `"String, Command"` from FuncSpec args. +fn synthesize_signature(args: &[(Ident, Type)]) -> String { + args.iter() + .map(|(_, ty)| type_to_sig_name(ty)) + .collect::>() + .join(", ") +} + fn expand_simple_include_native(simple: IncludeNativeSimple) -> TokenStream { let name = simple.name; let type_path = simple.type_path; let methods = simple.methods; - + + let type_name_str = quote!(#type_path).to_string().replace(' ', ""); + let method_names: Vec = methods.iter().map(|m| m.name.to_string()).collect(); + let method_sigs: Vec = methods.iter().map(|m| synthesize_signature(&m.args)).collect(); + let method_calls = methods.iter().map(|method| { let method_name = method.name.to_string(); let method_ident = &method.name; + let signature = synthesize_signature(&method.args); let arg_extractions = generate_arg_extraction(&method.args); let arg_passings = generate_arg_passing(&method.args); - + quote! { - .method(#method_name, |args| { + .method(#method_name, #signature, |args| { #(#arg_extractions)* let this = mize::prelude::get_global_mize()? .get_config(#name)? @@ -249,12 +275,26 @@ fn expand_simple_include_native(simple: IncludeNativeSimple) -> TokenStream { }) } }); - + let expanded = quote! { - mize::config::opt(#name) - #(#method_calls)* + { + if let Ok(mize) = mize::prelude::get_global_mize() { + if mize.is_generate_mode().unwrap_or(false) { + let _ = mize.record_native( + #name, + #type_name_str, + Vec::new(), + vec![#(#method_names.to_string()),*], + Vec::new(), + vec![#(#method_sigs.to_string()),*], + ); + } + } + mize::config::opt(#name) + #(#method_calls)* + } }; - + TokenStream::from(expanded) } @@ -263,15 +303,22 @@ fn expand_block_include_native(block: IncludeNativeBlock) -> TokenStream { let type_path = block.type_path; let associated = block.associated; let methods = block.methods; - + + let type_name_str = quote!(#type_path).to_string().replace(' ', ""); + let associated_names: Vec = associated.iter().map(|m| m.name.to_string()).collect(); + let method_names: Vec = methods.iter().map(|m| m.name.to_string()).collect(); + let associated_sigs: Vec = associated.iter().map(|m| synthesize_signature(&m.args)).collect(); + let method_sigs: Vec = methods.iter().map(|m| synthesize_signature(&m.args)).collect(); + let method_calls = methods.iter().map(|method| { let method_name = method.name.to_string(); let method_ident = &method.name; + let signature = synthesize_signature(&method.args); let arg_extractions = generate_arg_extraction(&method.args); let arg_passings = generate_arg_passing(&method.args); - + quote! { - .method(#method_name, |args| { + .method(#method_name, #signature, |args| { #(#arg_extractions)* let this = mize::prelude::get_global_mize()? .get_config(#name)? @@ -281,28 +328,43 @@ fn expand_block_include_native(block: IncludeNativeBlock) -> TokenStream { }) } }); - + let associated_calls = associated.iter().map(|func| { let func_name = func.name.to_string(); let func_ident = &func.name; + let signature = synthesize_signature(&func.args); let arg_extractions = generate_arg_extraction(&func.args); let arg_passings = generate_arg_passing(&func.args); - + quote! { - .method(#func_name, |args| { + .method(#func_name, #signature, |args| { #(#arg_extractions)* let result = <#type_path>::#func_ident(#(#arg_passings),*); Ok(mize::item::ItemData::from_native(result)?) }) } }); - + let expanded = quote! { - mize::config::opt(#name) - #(#associated_calls)* - #(#method_calls)* + { + if let Ok(mize) = mize::prelude::get_global_mize() { + if mize.is_generate_mode().unwrap_or(false) { + let _ = mize.record_native( + #name, + #type_name_str, + vec![#(#associated_names.to_string()),*], + vec![#(#method_names.to_string()),*], + vec![#(#associated_sigs.to_string()),*], + vec![#(#method_sigs.to_string()),*], + ); + } + } + mize::config::opt(#name) + #(#associated_calls)* + #(#method_calls)* + } }; - + TokenStream::from(expanded) } diff --git a/md b/md deleted file mode 100755 index aafc119..0000000 --- a/md +++ /dev/null @@ -1,149 +0,0 @@ -#!/bin/sh -set -e - -MIZE_SRC="/home/me/work/config/mize" # hardcoded for now -RSYNC_EXCLUDES="--exclude=node_modules --exclude=target --exclude=mize_config.toml --exclude=rust_dist --exclude=deno_dist --exclude=dist --exclude=result --exclude=pkg" - -function main { - if [[ "$1" == "gen" ]]; then - generate_sources - fi - - if [[ "$1" == "dsp" ]]; then - deploy_spacetime - fi - - if [[ "$1" == "dlu" ]]; then - deploy_lush - fi - - if [[ "$1" == "dma" ]]; then - deploy_main - fi - - if [[ "$1" == "dmac" ]]; then - deploy_mac - fi - - if [[ "$1" == "dpw" ]]; then - deploy_ppc_website - fi - - if [[ "$1" == "dmo" ]]; then - deploy_main_obsidian - fi -} - -function deploy_spacetime { - spacetime publish -p $MIZE_SRC/packages/spacetime -} - -function generate_sources { - echo "mize: Generating sources..." - mkdir -p $MIZE_SRC/packages/generated/src/spacetime - - # Generate Cargo.toml and lib.rs -cat << 'EOF' > $MIZE_SRC/packages/generated/Cargo.toml -[package] -name = "generated" -version = "0.1.0" -edition = "2021" - -[lib] -name = "generated" -path = "src/lib.rs" - -[dependencies] -spacetimedb-sdk = "2.1.0" -EOF - echo -e 'pub mod spacetime;\n' > $MIZE_SRC/packages/generated/src/lib.rs - - # Generate spacetime client bindings - spacetime generate -p $MIZE_SRC/packages/spacetime -o $MIZE_SRC/packages/generated/src/spacetime --lang rust -} - -function deploy_main { - mkdir -p ~/here/mize/lib - cargo build --manifest-path $MIZE_SRC/packages/mize/Cargo.toml - cargo build --manifest-path $MIZE_SRC/packages/ppc/Cargo.toml --features desktop - - systemctl --user stop mize - - cp $MIZE_SRC/target/debug/mize ~/here/mize/ - cp $MIZE_SRC/target/debug/libppc.so ~/here/mize/lib/libppc_part.so - cp $MIZE_SRC/md ~/here/mize/ - cp $MIZE_SRC/target/debug/ppc ~/here/mize/ - - systemctl --user start mize -} - -function deploy_mac { - echo "c2vi: Deploying to mac..." - - # Copy files to mac - rsync -r -u -v -a --delete --include=".git/" --include=".git/**" --mkpath $RSYNC_EXCLUDES $MIZE_SRC mac:here - - # compile - ssh mac << EOF - if ! tmux has-session -t ppc-deploy 2>/dev/null; then - echo "Created new tmux session...." - tmux new-session -d -s ppc-deploy "nix develop git+file:///home/me/here/mize#buildShell" - tmux send-keys -t ppc-deploy "cargo build --manifest-path /home/me/here/mize/packages/mize/Cargo.toml" Enter - tmux send-keys -t ppc-deploy "cargo build --features desktop --manifest-path /home/me/here/mize/packages/ppc/Cargo.toml" Enter - tmux send-keys -t ppc-deploy "systemctl --user restart mize" Enter - else - echo "using existing session..." - tmux send-keys -t ppc-deploy "cargo build --manifest-path /home/me/here/mize/packages/mize/Cargo.toml" Enter - tmux send-keys -t ppc-deploy "cargo build --features desktop --manifest-path /home/me/here/mize/packages/ppc/Cargo.toml" Enter - tmux send-keys -t ppc-deploy "systemctl --user restart mize" Enter - fi -EOF -} - -function deploy_lush { - echo "c2vi: Deploying to lush..." - - # Copy files to lush - rsync -r -u -v -a --delete --include=".git/" --include=".git/**" --mkpath $RSYNC_EXCLUDES $MIZE_SRC lush:here - - # compile - ssh lush << EOF - if ! tmux has-session -t ppc-deploy 2>/dev/null; then - echo "Created new tmux session...." - tmux new-session -d -s ppc-deploy "nix develop git+file:///home/me/here/mize#buildShell" - tmux send-keys -t ppc-deploy "cargo build --manifest-path /home/me/here/mize/packages/mize/Cargo.toml" Enter - tmux send-keys -t ppc-deploy "cargo build --features desktop --manifest-path /home/me/here/mize/packages/ppc/Cargo.toml" Enter - tmux send-keys -t ppc-deploy "systemctl --user restart mize" Enter - else - echo "using existing session..." - tmux send-keys -t ppc-deploy "cargo build --manifest-path /home/me/here/mize/packages/mize/Cargo.toml" Enter - tmux send-keys -t ppc-deploy "cargo build --features desktop --manifest-path /home/me/here/mize/packages/ppc/Cargo.toml" Enter - tmux send-keys -t ppc-deploy "systemctl --user restart mize" Enter - fi -EOF - -} - -function deploy_ppc_website { - echo "c2vi: Deploying ppc website to fes" - - # compile - cargo build --release --no-default-features --features server --manifest-path $MIZE_SRC/packages/ppc/Cargo.toml - - ssh fes rm /home/server/here/ppc - # upload - scp $MIZE_SRC/target/release/ppc fes:here - - # restart service - ssh fe "sudo systemctl restart ppc" -} - -function deploy_main_obsidian { - echo "c2vi: Deploying to local main obsidian vault..." - - deno run --config $MIZE_SRC/packages/ppc/platform/obsidian/deno.json build - - cp -r $MIZE_SRC/packages/ppc/platform/obsidian/dist/* ~/work/things/.obsidian/plugins/ppc/ -} - -main "$@" diff --git a/parts/auth.client/Cargo.toml b/parts/auth.client/Cargo.toml new file mode 100644 index 0000000..8190ea0 --- /dev/null +++ b/parts/auth.client/Cargo.toml @@ -0,0 +1,39 @@ +cargo-features = ["profile-rustflags"] + +[package] +name = "mize-part-auth-client" +version = "0.1.0" +edition = "2024" + +[lib] +name = "mize_part_auth_client" +crate-type = [ "cdylib", "rlib" ] + +[features] +default = [ "target-os" ] +target-os = [ "webbrowser" ] +target-js = [] +target-obsidian = [ "target-js" ] + +[dependencies] +mize = { workspace = true } +log = "0.4.34" +mize-generated-auth = { path = "./generated" } +webbrowser = { version = "1.2.0", optional = true } +serde = "1.0.228" +serde_json = "1.0.149" +tokio = { version = "1.49.0", default-features = false, features = ["time"] } +openidconnect = { version = "4", features = ["reqwest", "rustls-tls"], default-features = false } +reqwest = { version = "0.11", default-features = false, features = ["rustls-tls-webpki-roots"] } +chrono = { version = "0.4.45", features = [], default-features = false } + + + + + + +[profile.dev] +rustflags = ["-C", "prefer-dynamic", "-C", "link-args=-Wl,--export-dynamic"] + +[profile.release] +rustflags = ["-C", "prefer-dynamic"] diff --git a/parts/auth.client/generated/Cargo.toml b/parts/auth.client/generated/Cargo.toml new file mode 100644 index 0000000..5ec102c --- /dev/null +++ b/parts/auth.client/generated/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "mize-generated-auth" +version = "0.1.0" +edition = "2024" + +[lib] +name = "mize_generated_auth" +path = "src/lib.rs" + +[dependencies] +mize = { workspace = true } diff --git a/parts/auth.client/generated/src/lib.rs b/parts/auth.client/generated/src/lib.rs new file mode 100644 index 0000000..73528b4 --- /dev/null +++ b/parts/auth.client/generated/src/lib.rs @@ -0,0 +1,92 @@ +// AUTO-GENERATED by mize dev gen -- do not edit manually +use mize::prelude::*; +use mize::config::MizeFun; + + +pub struct CliPart { + id: MizeId +} + +impl MizePart for CliPart { + fn id(&self) -> MizeResult { + Ok(self.id.clone()) + } +} + +impl CliPart { + pub fn get(name: &str) -> MizeResult { + let mut mize = get_global_mize()?; + let part = mize.get_part(name)?; + Ok(CliPart { id: part.id()? }) + } + + pub fn set_command(&self, arg0: &str) -> MizeResult<()> { + let mut args = ItemData::new(); + args.set_path("0", arg0.into_item_data())?; + dyn_call(self.id.clone(), "set_command", args)?; + Ok(()) + } + + pub fn subcommand(&self, arg0: Command, arg1: MizeFun) -> MizeResult<()> { + let mut args = ItemData::new(); + let mut __arg0 = ItemData::new(); + __arg0.set_path("_native", arg0.native_num)?; + args.set_path("0", __arg0)?; + args.set_path("1", ItemData::fun(arg1)?)?; + dyn_call(self.id.clone(), "subcommand", args)?; + Ok(()) + } + + pub fn run(&self, arg0: Vec) -> MizeResult<()> { + let mut args = ItemData::new(); + args.set_path("0", arg0.into_item_data())?; + dyn_call(self.id.clone(), "run", args)?; + Ok(()) + } + + pub fn opt_state(&self) -> MizeResult { + get_config(&format!("{}/state", self.id.dot())) + } + +} + +// native type: Command (clap::Command) +pub struct Command { + pub native_num: u32 +} + +impl FromItemData for Command { + fn from_itemdata(data: ItemData) -> MizeResult { + Ok(Command { native_num: data.get_path("_native")?.value_u32()? }) + } +} + +impl Command { + pub fn new(arg0: &str) -> MizeResult { + let mut args = ItemData::new(); + args.set_path("0", arg0.into_item_data())?; + let mut mize = get_global_mize()?; + let id = mize.id_new_dots("cli.Command")?; + let data = dyn_call(id, "new", args)?; + let native_num: u32 = data.get_path("_native")?.value_u32()?; + Ok(Command { native_num }) + } + +} + +// native type: ArgMatches (clap::ArgMatches) +pub struct ArgMatches { + pub native_num: u32 +} + +impl FromItemData for ArgMatches { + fn from_itemdata(data: ItemData) -> MizeResult { + Ok(ArgMatches { native_num: data.get_path("_native")?.value_u32()? }) + } +} + +impl ArgMatches { +} + +// part id string: cli + diff --git a/parts/auth.client/part b/parts/auth.client/part new file mode 100644 index 0000000..4484765 --- /dev/null +++ b/parts/auth.client/part @@ -0,0 +1,2 @@ +id = "auth.client" +gen = [ "cli" ] diff --git a/parts/auth/src/client.rs b/parts/auth.client/src/lib.rs similarity index 83% rename from parts/auth/src/client.rs rename to parts/auth.client/src/lib.rs index 175e6fb..4f8764f 100644 --- a/parts/auth/src/client.rs +++ b/parts/auth.client/src/lib.rs @@ -1,22 +1,16 @@ use chrono::{DateTime, TimeDelta, Utc}; -use mize::config::OptVal; -use mize::config::thread; -use mize::include_native; use mize::prelude::*; -use mize::out; -use mize::{ - item::ItemData, mize_err, mize_part, Mize, MizeError, MizePart, MizePartCreate, MizeResult, -}; use openidconnect::{ ClientId, DeviceAuthorizationResponse, EmptyExtraDeviceAuthorizationFields, IssuerUrl, OAuth2TokenResponse, RefreshToken, Scope, TokenResponse, }; use serde::{Deserialize, Serialize}; +use tokio::runtime::Runtime; use std::fs::OpenOptions; use std::io::Write; use std::{path::PathBuf, thread}; use tracing::{info, warn}; -use mize_part_cli::CliPartState; +use mize_generated_auth::*; // console_log macro // that can be copied into other files for debugging purposes @@ -37,16 +31,6 @@ macro_rules! console_log { ($($t:tt)*) => (unsafe { log(&format_args!($($t)*).to_string())}) } -#[cfg(feature = "target-os")] -use mize_part_cli::clap::Command; - -#[derive(Default)] -#[mize_part] -pub struct ClientAuth { - mize: Mize, - secrets: Option, -} - #[derive(Default, Serialize, Deserialize, Clone, Debug)] pub struct ClientSecrets { id_token: String, @@ -55,14 +39,6 @@ pub struct ClientSecrets { expiry: DateTime, } -impl MizePartCreate for ClientAuth {} - -impl MizePart for ClientAuth { - fn name(&self) -> &'static str { - "client_auth" - } -} - #[cfg(feature = "target-js")] pub fn store_secrets_js(mize: &Mize, secrets: &ClientSecrets) -> MizeResult<()> { use web_sys::window; @@ -85,6 +61,7 @@ pub fn store_secrets_js(mize: &Mize, secrets: &ClientSecrets) -> MizeResult<()> } +/* impl ClientAuth { pub fn secrets(&self) -> Option<&ClientSecrets> { self.secrets.as_ref() @@ -173,20 +150,59 @@ impl ClientAuth { } } - + */ + +async fn test() { + let client = reqwest::Client::builder().tls_built_in_root_certs(true).no_proxy().build().unwrap(); + let req = client.get("https://orf.at").build().unwrap(); + let res = client.execute(req).await.unwrap(); + println!("res: {:?}", res); } #[unsafe(no_mangle)] -pub extern "C" fn part_auth() -> MizeResult<()> { +pub extern "C" fn part_auth_client() -> MizeResult<()> { - opt("cred") - .fun(|| { - let mize = get_global_mize()?; - let secrets = do_login()?; - ItemData::from_serializable(secrets) - }); + opt("secrets") + .fun(Box::new(|| { + let mut mize = get_global_mize()?; + if let Ok(secrets) = load_secrets(&mut mize) { + if secrets.expiry < Utc::now() { + if let Ok(fresh_secrets) = mize.spawn_async_blocking("refresh", refresh_flow(mize.clone(), secrets.clone())) { + return ItemData::from_serializable(Some(fresh_secrets)); + } + } + return ItemData::from_serializable(Some(secrets)); + } else { + return ItemData::from_serializable::>(None); + } + })); - let mize = get_global_mize()?; + method("login", "() -> ()", |_args| { + #[cfg(feature = "target-os")] { + println!("hiiiii"); + let mut mize = get_global_mize()?; + + // i hate rust. + let runtime = Runtime::new()?; + let guard = runtime.enter(); + std::mem::forget(guard); + + println!("hiiiii"); + match do_login() { + Ok(secrets) => { + store_secrets(&mut mize, &secrets)?; + notify_mme_login_state(true)?; + } + Err(err) => { + notify_mme_login_state(false)?; + return Err(err); + } + } + } + Ok(ItemData::new()) + }); + + let mut mize = get_global_mize()?; // start refresh tread if configured if mize @@ -195,41 +211,21 @@ pub extern "C" fn part_auth() -> MizeResult<()> { .value_bool() .unwrap_or(false) { - thread("auth.refresh_thread", start_refresh_thread()); + thread("auth.refresh_thread", start_refresh_thread); } - - let cli = get_part_gen::("cli"); + // cli command for os #[cfg(feature = "target-os")] { - println!("hasdfaslkjfasldkfj"); - let cli_dyn = mize.get_part("cli")?; - println!("hasdfaslkjfasldkfj three "); - let mut cli = mize_part_cli::downcast_cli_part(cli_dyn)?; - println!("hasdfaslkjfasldkfj two "); + let cli = CliPart::get("cli")?; //let mut cli = mize.get_part_native::("cli")?; cli.set_command("ppc"); - cli.subcommand(Command::new("login"), move |_, mut mize| { - let mut auth = mize.get_part_native::("client_auth")?; - let secrets = if auth.secrets.is_some() { - match mize.spawn_async_blocking( - "client_auth", - refresh_flow(mize.clone(), auth.secrets.clone().unwrap()), - ) { - Ok(secrets) => secrets, - Err(err) => { - out!("err refreshing secrets: {:?}", err); - mize.spawn_async_blocking("client_auth", auth_flow(mize_clone.clone()))? - } - } - } else { - mize.spawn_async_blocking("client_auth", auth_flow(mize_clone.clone()))? - }; - store_secrets(&mut mize, &secrets)?; - auth.secrets = Some(secrets); - Ok(()) - })?; + cli.subcommand(Command::new("login")?, Box::new(|_| { + let mut mize = get_global_mize()?; + dyn_call(mize.id_new_dots("auth.client")?, "login", ItemData::new())?; + Ok(ItemData::new()) + }))?; } @@ -251,24 +247,20 @@ pub extern "C" fn part_auth() -> MizeResult<()> { })?; } - - auth_part.secrets = secrets; - - mize.register_part(Box::new(auth_part))?; - Ok(()) } -pub fn start_refresh_thread() -> MizeResult<()> { +pub fn start_refresh_thread(_args: ItemData) -> MizeResult { // background thread for os targets #[cfg(feature = "target-os")] { - let mut mize_clone = self.mize.clone(); - self.mize.spawn_background("auth.refresh", move || loop { + let mut mize = get_global_mize()?; + mize.spawn_background("auth.refresh", move || loop { + let mut mize = get_global_mize()?; info!("hi from auth.refresh thread..."); thread::sleep(Duration::from_secs(33)); // TERRIBLE hack - let auth = mize_clone.get_part_native::("client_auth")?; - let expiry = auth.secrets.as_ref().unwrap().expiry.clone(); + let secrets = get_config("self.secrets")?.native::()?; + let expiry = secrets.expiry.clone(); info!("auth.refresh thread: now: {}", Utc::now()); info!("auth.refresh thread: expiry: {}", expiry); let to_sleep = expiry - Utc::now() - TimeDelta::minutes(20); @@ -279,17 +271,13 @@ pub fn start_refresh_thread() -> MizeResult<()> { } } */ - drop(auth); info!("auth.refresh: thread going to sleep for: {}", to_sleep); thread::sleep(to_sleep.to_std()?); info!("refresh_thread: sleeping done"); - let mut auth = mize_clone.get_part_native::("auth")?; - auth.refresh()?; - drop(auth); + dyn_call(mize.id_new_dots("auth.client")?, "refresh", ItemData::new())?; })?; - Ok(()) } /* @@ -345,25 +333,52 @@ pub fn start_refresh_thread() -> MizeResult<()> { } */ - Ok(()) + Ok(ItemData::new()) } fn do_login() -> MizeResult { let mut mize = get_global_mize()?; let mut secrets; if let Ok(val) = load_secrets(&mut mize) { - if val.clone().unwrap().expiry < Utc::now() { + if val.clone().expiry < Utc::now() { // refresh if secrets are expired - secrets = mize.spawn_async_blocking("auth.refresh", refresh_flow(mize, val))?; + secrets = match mize.spawn_async_blocking("auth.refresh", refresh_flow(mize.clone(), val)) { + Ok(secrets) => secrets, + Err(err) => { + out!("err refreshing secrets: {:?}", err); + mize.spawn_async_blocking("auth.login", auth_flow(mize.clone()))? + } + }; } else { secrets = val; } } else { - secrets = mize.spawn_async_blocking("auth.login", auth_flow(mize))?; + secrets = mize.spawn_async_blocking("auth.login", auth_flow(mize.clone()))?; } Ok(secrets) } +fn notify_mme_url_and_code(url: &str, code: &str) -> MizeResult<()> { + let mut mize = get_global_mize()?; + if mize.has_part("mme")? { + let mut args = ItemData::new(); + args.set_path("0", url.to_owned().into_item_data())?; + args.set_path("1", code.to_owned().into_item_data())?; + dyn_call(mize.id_new_dots("mme")?, "set_url_and_code", args)?; + } + Ok(()) +} + +fn notify_mme_login_state(logged_in: bool) -> MizeResult<()> { + let mut mize = get_global_mize()?; + if mize.has_part("mme")? { + let mut args = ItemData::new(); + args.set_path("0", logged_in.into_item_data())?; + dyn_call(mize.id_new_dots("mme")?, "set_login_state", args)?; + } + Ok(()) +} + fn load_secrets(mize: &mut Mize) -> MizeResult { #[cfg(feature = "target-os")] { let mize_dir = mize.get_config("data_dir")?.value_string()?; @@ -517,7 +532,8 @@ async fn auth_flow(mut mize: Mize) -> MizeResult { let issuer = IssuerUrl::new(issuer)?; let client_id = ClientId::new(client_id); - let http_client = HttpClient::new(); + let http_client = openidconnect::reqwest::Client::builder().tls_built_in_root_certs(true).build()?; + // Teach openidconnect-rs about the device authorization url. #[derive(Clone, Debug, Deserialize, Serialize)] @@ -550,7 +566,7 @@ async fn auth_flow(mut mize: Mize) -> MizeResult { // Discover provider metadata let provider_metadata: MyProviderMetadata = - MyProviderMetadata::discover_async(issuer, &http_client).await?; + MyProviderMetadata::discover_async(issuer, &http_client).await.map_err(|e| mize_err!("From reqwest::error::Error: {e}"))?; let device_auth_url = provider_metadata .additional_metadata() @@ -601,18 +617,23 @@ async fn auth_flow(mut mize: Mize) -> MizeResult { } #[cfg(feature = "target-os")] { + let url = details + .verification_uri_complete() + .map(|u| u.secret().clone()) + .unwrap_or_default(); + let code = details.user_code().secret().clone(); + + let _ = notify_mme_url_and_code(&url, &code); + out!( "If your browser does not open automatically, open this URL in it:\n{}\n", - details.verification_uri_complete().unwrap().secret() - ); - out!( - "Or enter this PPC login code:\n{}\n", - details.user_code().secret() + url ); + out!("Or enter this PPC login code:\n{}\n", code); - if let Some(_) = details.verification_uri_complete() { - let _ = webbrowser::open(details.verification_uri_complete().unwrap().secret()); - } + if !url.is_empty() { + let _ = webbrowser::open(&url); + } } let token_response = client diff --git a/parts/auth/src/lib.rs b/parts/auth/src/lib.rs deleted file mode 100644 index 74bfa92..0000000 --- a/parts/auth/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ - -pub mod auth { - pub mod client; - pub use client::*; -} -pub use auth::*; diff --git a/parts/cli/src/lib.rs b/parts/cli/src/lib.rs index 8d229c6..f9737dc 100644 --- a/parts/cli/src/lib.rs +++ b/parts/cli/src/lib.rs @@ -11,6 +11,8 @@ pub extern "C" fn part_cli() -> MizeResult<()> { //methods: [arg(arg: clap::Arg), subcommand(cmd: clap::Command)] }); + include_native!("ArgMatches", clap::ArgMatches, {}); + opt("state") .fun(Box::new(|| { let mize = get_global_mize().unwrap(); @@ -25,7 +27,7 @@ pub extern "C" fn part_cli() -> MizeResult<()> { })); - method("set_command", |args| { + method("set_command", "String -> ()", |args| { let mut state = get_config("self.state")?.native_mut::()?; let cmd = args.get_path("0")?.native::()?; state.current_cmd_name = cmd.to_owned(); @@ -36,7 +38,7 @@ pub extern "C" fn part_cli() -> MizeResult<()> { Ok(ItemData::new()) }); - method("subcommand", |args| { + method("subcommand", "Command, Func -> ()", |args| { let mut state = get_config("self.state")?.native_mut::()?; let subcmd = args.get_path("0")?.native_take::()?; let action = args.get_path("1")?; @@ -52,7 +54,7 @@ pub extern "C" fn part_cli() -> MizeResult<()> { Ok(ItemData::new()) }); - method("run", |args| { + method("run", "Vec -> ()", |args| { let cmdline = args.get_path("0")?.native_take::>()?; let mut state = get_config("self.state")?.native_mut::()?; let cmd_name = cmdline.iter().nth(0).ok_or(mize_err!("empty cmdline"))?; diff --git a/parts/mize.dev/docker/base/Dockerfile b/parts/mize.dev/docker/base/Dockerfile new file mode 100644 index 0000000..0acc394 --- /dev/null +++ b/parts/mize.dev/docker/base/Dockerfile @@ -0,0 +1,32 @@ +FROM rust:1.95.0 + +RUN apt-get update + +RUN apt-get install -y \ + mingw-w64 \ + build-essential \ + gcc-arm-linux-gnueabi \ + g++-arm-linux-gnueabi + +RUN apt-get install -y \ + clang \ + lld \ + llvm + +# Rust cross-compilation targets +RUN rustup target add --toolchain nightly-2026-01-30 x86_64-pc-windows-gnu + +RUN rustup target add --toolchain nightly-2026-01-30 aarch64-pc-windows-gnullvm + +RUN rustup target add --toolchain nightly-2026-01-30 x86_64-unknown-linux-gnu + +RUN rustup target add --toolchain nightly-2026-01-30 aarch64-unknown-linux-gnu + +RUN rustup target add --toolchain nightly-2026-01-30 armv7-unknown-linux-gnueabihf + +RUN rustup target add --toolchain nightly-2026-01-30 arm-unknown-linux-gnueabi + +# Set default Rust toolchain +RUN rustup default nightly-2026-01-30 + +WORKDIR /src diff --git a/parts/mize.dev/docker/darwin/Dockerfile b/parts/mize.dev/docker/darwin/Dockerfile new file mode 100644 index 0000000..7e5b2df --- /dev/null +++ b/parts/mize.dev/docker/darwin/Dockerfile @@ -0,0 +1,8 @@ +FROM joseluisq/rust-linux-darwin-builder:2.0.0-beta.1 + +RUN rustup target add --toolchain nightly-2026-01-30 x86_64-apple-darwin +RUN rustup target add --toolchain nightly-2026-01-30 aarch64-apple-darwin + +RUN rustup default nightly-2026-01-30 + +WORKDIR /src diff --git a/parts/mize.dev/src/codegen.rs b/parts/mize.dev/src/codegen.rs index a930855..efb327d 100644 --- a/parts/mize.dev/src/codegen.rs +++ b/parts/mize.dev/src/codegen.rs @@ -4,7 +4,8 @@ //! a Rust source file that looks like the hand-written `generated.rs`. use mize::prelude::*; -use mize::instance::{PartMetadata, MethodMetadata, OptMetadata, NativeMetadata}; +use mize::instance::{PartMetadata, MethodMetadata, OptMetadata, NativeMetadata, parse_method_signature}; +use std::collections::HashSet; use std::fmt::Write as _; /// Convert a part name like "cli" into a PascalCase struct name like "CliPart". @@ -31,7 +32,8 @@ fn part_name_to_struct(part_name: &str) -> String { pub fn generate_lib_rs(all_metadata: &[PartMetadata]) -> String { let mut out = String::new(); out.push_str("// AUTO-GENERATED by mize dev gen -- do not edit manually\n"); - out.push_str("use mize::prelude::*;\n\n\n"); + out.push_str("use mize::prelude::*;\n"); + out.push_str("use mize::config::MizeFun;\n\n\n"); for meta in all_metadata { generate_part_struct(&mut out, meta); @@ -40,9 +42,28 @@ pub fn generate_lib_rs(all_metadata: &[PartMetadata]) -> String { out } +fn native_names(meta: &PartMetadata) -> HashSet { + meta.natives.iter().map(|n| n.name.clone()).collect() +} + +fn native_fn_names(meta: &PartMetadata) -> HashSet { + let mut names = HashSet::new(); + for n in &meta.natives { + for a in &n.associated { + names.insert(a.clone()); + } + for m in &n.methods { + names.insert(m.clone()); + } + } + names +} + fn generate_part_struct(out: &mut String, meta: &PartMetadata) { let struct_name = part_name_to_struct(&meta.part_name); let part_id_str = meta.part_name.replace('.', "."); + let natives = native_names(meta); + let native_fns = native_fn_names(meta); // struct definition let _ = writeln!(out, "pub struct {struct_name} {{"); @@ -52,8 +73,8 @@ fn generate_part_struct(out: &mut String, meta: &PartMetadata) { // MizePart impl let _ = writeln!(out, "impl MizePart for {struct_name} {{"); - let _ = writeln!(out, " fn id(&self) -> MizeId {{"); - let _ = writeln!(out, " self.id.clone()"); + let _ = writeln!(out, " fn id(&self) -> MizeResult {{"); + let _ = writeln!(out, " Ok(self.id.clone())"); let _ = writeln!(out, " }}"); let _ = writeln!(out, "}}"); let _ = writeln!(out); @@ -65,16 +86,23 @@ fn generate_part_struct(out: &mut String, meta: &PartMetadata) { let _ = writeln!(out, " pub fn get(name: &str) -> MizeResult<{struct_name}> {{"); let _ = writeln!(out, " let mut mize = get_global_mize()?;"); let _ = writeln!(out, " let part = mize.get_part(name)?;"); - let _ = writeln!(out, " Ok({struct_name} {{ id: part.id() }})"); + let _ = writeln!(out, " Ok({struct_name} {{ id: part.id()? }})"); let _ = writeln!(out, " }}"); + let _ = writeln!(out); - // one method per recorded method/effect/thread + // part methods (skip ones that belong to include_native) for m in meta.methods.iter().chain(meta.effects.iter()).chain(meta.threads.iter()) { - generate_method_fn(out, &struct_name, m); + if native_fns.contains(&m.name) { + continue; + } + generate_typed_method_fn(out, &struct_name, m); } - // one getter-ish fn per recorded opt (opts are config values; expose a dyn_call getter) + // opts that are not natives for o in &meta.opts { + if natives.contains(&o.name) || o.name.starts_with('_') { + continue; + } generate_opt_fn(out, &struct_name, o); } @@ -83,22 +111,143 @@ fn generate_part_struct(out: &mut String, meta: &PartMetadata) { // native type wrappers for n in &meta.natives { - generate_native_struct(out, n); + generate_native_struct(out, &meta.part_name, n); } let _ = writeln!(out, "// part id string: {part_id_str}"); let _ = writeln!(out); } -fn generate_method_fn(out: &mut String, _struct_name: &str, m: &MethodMetadata) { +/// Map a signature type name to a Rust parameter type for generated bindings. +fn rust_param_type(type_name: &str) -> String { + match type_name { + "String" => "&str".to_string(), + "u32" => "u32".to_string(), + "Vec" => "Vec".to_string(), + "Func" => "MizeFun".to_string(), + "()" => "()".to_string(), + other => other.to_string(), // native wrapper type + } +} + +fn is_native_type(type_name: &str) -> bool { + !matches!( + type_name, + "String" | "u32" | "Vec" | "Func" | "()" | "ItemData" | "" + ) +} + +/// Emit packing of one typed arg into `args` at path index `i`. +fn emit_arg_pack(out: &mut String, i: usize, type_name: &str, param_name: &str) { + match type_name { + "String" => { + let _ = writeln!( + out, + " args.set_path(\"{i}\", {param_name}.into_item_data())?;" + ); + } + "u32" => { + let _ = writeln!( + out, + " args.set_path(\"{i}\", {param_name}.into_item_data())?;" + ); + } + "Vec" => { + let _ = writeln!( + out, + " args.set_path(\"{i}\", {param_name}.into_item_data())?;" + ); + } + "Func" => { + let _ = writeln!( + out, + " args.set_path(\"{i}\", ItemData::fun({param_name})?)?;" + ); + } + _ if is_native_type(type_name) => { + let _ = writeln!(out, " let mut __arg{i} = ItemData::new();"); + let _ = writeln!( + out, + " __arg{i}.set_path(\"_native\", {param_name}.native_num)?;" + ); + let _ = writeln!(out, " args.set_path(\"{i}\", __arg{i})?;"); + } + _ => { + let _ = writeln!( + out, + " args.set_path(\"{i}\", {param_name}.into_item_data())?;" + ); + } + } +} + +fn generate_typed_method_fn( + out: &mut String, + _struct_name: &str, + m: &MethodMetadata, +) { let fn_name = &m.name; - let _ = writeln!( - out, - " pub fn {fn_name}(&self, args: ItemData) -> MizeResult {{" - ); - let _ = writeln!(out, " dyn_call(self.id.clone(), \"{fn_name}\", args)?;"); - // note: dyn_call returns ItemData already, so wrap: - let _ = writeln!(out, " dyn_call(self.id.clone(), \"{fn_name}\", args)"); + let (arg_types, return_type) = if m.arg_types.is_empty() && m.return_type.is_empty() && !m.signature.is_empty() { + parse_method_signature(&m.signature) + } else { + (m.arg_types.clone(), m.return_type.clone()) + }; + + let params: Vec<(String, String)> = arg_types + .iter() + .enumerate() + .map(|(i, t)| (format!("arg{i}"), rust_param_type(t))) + .collect(); + + let ret_ty = match return_type.as_str() { + "()" => "()".to_string(), + "" | "ItemData" => "ItemData".to_string(), + other => other.to_string(), + }; + + let param_list = params + .iter() + .map(|(n, t)| format!("{n}: {t}")) + .collect::>() + .join(", "); + + if param_list.is_empty() { + let _ = writeln!( + out, + " pub fn {fn_name}(&self) -> MizeResult<{ret_ty}> {{" + ); + } else { + let _ = writeln!( + out, + " pub fn {fn_name}(&self, {param_list}) -> MizeResult<{ret_ty}> {{" + ); + } + + let _ = writeln!(out, " let mut args = ItemData::new();"); + for (i, t) in arg_types.iter().enumerate() { + emit_arg_pack(out, i, t, &format!("arg{i}")); + } + + match ret_ty.as_str() { + "()" => { + let _ = writeln!(out, " dyn_call(self.id.clone(), \"{fn_name}\", args)?;"); + let _ = writeln!(out, " Ok(())"); + } + "ItemData" => { + let _ = writeln!(out, " dyn_call(self.id.clone(), \"{fn_name}\", args)"); + } + native if is_native_type(native) => { + let _ = writeln!(out, " let data = dyn_call(self.id.clone(), \"{fn_name}\", args)?;"); + let _ = writeln!( + out, + " Ok({native} {{ native_num: data.get_path(\"_native\")?.value_u32()? }})" + ); + } + _ => { + let _ = writeln!(out, " dyn_call(self.id.clone(), \"{fn_name}\", args)"); + } + } + let _ = writeln!(out, " }}"); let _ = writeln!(out); } @@ -114,40 +263,210 @@ fn generate_opt_fn(out: &mut String, _struct_name: &str, o: &OptMetadata) { let _ = writeln!(out); } -fn generate_native_struct(out: &mut String, n: &NativeMetadata) { +fn generate_native_struct(out: &mut String, part_name: &str, n: &NativeMetadata) { let struct_name = &n.name; let _ = writeln!(out, "// native type: {} ({})", n.name, n.type_name); let _ = writeln!(out, "pub struct {struct_name} {{"); - let _ = writeln!(out, " native_id: u32"); + let _ = writeln!(out, " pub native_num: u32"); let _ = writeln!(out, "}}"); let _ = writeln!(out); + + let _ = writeln!(out, "impl FromItemData for {struct_name} {{"); + let _ = writeln!(out, " fn from_itemdata(data: ItemData) -> MizeResult {{"); + let _ = writeln!( + out, + " Ok({struct_name} {{ native_num: data.get_path(\"_native\")?.value_u32()? }})" + ); + let _ = writeln!(out, " }}"); + let _ = writeln!(out, "}}"); + let _ = writeln!(out); + let _ = writeln!(out, "impl {struct_name} {{"); - for assoc in &n.associated { - let _ = writeln!( - out, - " pub fn {assoc}(args: ItemData) -> MizeResult {{" - ); - let _ = writeln!(out, " let mut mize = get_global_mize()?;"); - let _ = writeln!(out, " let id = mize.id_new_dots(\"{}.{assoc}\")?;", n.name); - let _ = writeln!(out, " dyn_call(id, \"{assoc}\", args)"); - let _ = writeln!(out, " }}"); + + for (i, assoc) in n.associated.iter().enumerate() { + let sig = n.associated_sigs.get(i).map(|s| s.as_str()).unwrap_or(""); + generate_native_associated(out, part_name, n, assoc, sig); } - for meth in &n.methods { - let _ = writeln!( - out, - " pub fn {meth}(&self, args: ItemData) -> MizeResult {{" - ); - let _ = writeln!(out, " let mut mize = get_global_mize()?;"); - let _ = writeln!(out, " let id = mize.id_new_dots(\"{}.{meth}\")?;", n.name); - let _ = writeln!(out, " dyn_call(id, \"{meth}\", args)"); - let _ = writeln!(out, " }}"); + + for (i, meth) in n.methods.iter().enumerate() { + let sig = n.method_sigs.get(i).map(|s| s.as_str()).unwrap_or(""); + generate_native_instance_method(out, part_name, n, meth, sig); } + let _ = writeln!(out, "}}"); let _ = writeln!(out); } +fn generate_native_associated(out: &mut String, part_name: &str, n: &NativeMetadata, fn_name: &str, signature: &str) { + let (arg_types, return_type) = parse_method_signature(signature); + let ret_ty = if return_type.is_empty() { + n.name.clone() + } else { + return_type + }; + + let params: Vec<(String, String)> = arg_types + .iter() + .enumerate() + .map(|(i, t)| (format!("arg{i}"), rust_param_type(t))) + .collect(); + let param_list = params + .iter() + .map(|(name, ty)| format!("{name}: {ty}")) + .collect::>() + .join(", "); + + if param_list.is_empty() { + let _ = writeln!(out, " pub fn {fn_name}() -> MizeResult<{ret_ty}> {{"); + } else { + let _ = writeln!( + out, + " pub fn {fn_name}({param_list}) -> MizeResult<{ret_ty}> {{" + ); + } + + let _ = writeln!(out, " let mut args = ItemData::new();"); + for (i, t) in arg_types.iter().enumerate() { + emit_arg_pack(out, i, t, &format!("arg{i}")); + } + let _ = writeln!(out, " let mut mize = get_global_mize()?;"); + let _ = writeln!(out, " let id = mize.id_new_dots(\"{part_name}.{}\")?;", n.name); + + if ret_ty == "()" { + let _ = writeln!(out, " dyn_call(id, \"{fn_name}\", args)?;"); + let _ = writeln!(out, " Ok(())"); + } else if ret_ty == "ItemData" { + let _ = writeln!(out, " dyn_call(id, \"{fn_name}\", args)"); + } else if is_native_type(&ret_ty) || ret_ty == n.name { + let _ = writeln!(out, " let data = dyn_call(id, \"{fn_name}\", args)?;"); + let _ = writeln!( + out, + " let native_num: u32 = data.get_path(\"_native\")?.value_u32()?;" + ); + let _ = writeln!(out, " Ok({ret_ty} {{ native_num }})"); + } else { + let _ = writeln!(out, " dyn_call(id, \"{fn_name}\", args)"); + } + let _ = writeln!(out, " }}"); + let _ = writeln!(out); +} + +fn generate_native_instance_method(out: &mut String, part_name: &str, n: &NativeMetadata, fn_name: &str, signature: &str) { + let (arg_types, return_type) = parse_method_signature(signature); + let ret_ty = if return_type.is_empty() { + "ItemData".to_string() + } else { + return_type + }; + + let params: Vec<(String, String)> = arg_types + .iter() + .enumerate() + .map(|(i, t)| (format!("arg{i}"), rust_param_type(t))) + .collect(); + let param_list = params + .iter() + .map(|(name, ty)| format!("{name}: {ty}")) + .collect::>() + .join(", "); + + if param_list.is_empty() { + let _ = writeln!( + out, + " pub fn {fn_name}(&self) -> MizeResult<{ret_ty}> {{" + ); + } else { + let _ = writeln!( + out, + " pub fn {fn_name}(&self, {param_list}) -> MizeResult<{ret_ty}> {{" + ); + } + + let _ = writeln!(out, " let mut args = ItemData::new();"); + for (i, t) in arg_types.iter().enumerate() { + emit_arg_pack(out, i, t, &format!("arg{i}")); + } + let _ = writeln!(out, " let mut mize = get_global_mize()?;"); + let _ = writeln!(out, " let id = mize.id_new_dots(\"{part_name}.{}\")?;", n.name); + + match ret_ty.as_str() { + "()" => { + let _ = writeln!(out, " dyn_call(id, \"{fn_name}\", args)?;"); + let _ = writeln!(out, " Ok(())"); + } + "ItemData" => { + let _ = writeln!(out, " dyn_call(id, \"{fn_name}\", args)"); + } + native if is_native_type(native) => { + let _ = writeln!(out, " let data = dyn_call(id, \"{fn_name}\", args)?;"); + let _ = writeln!( + out, + " Ok({native} {{ native_num: data.get_path(\"_native\")?.value_u32()? }})" + ); + } + _ => { + let _ = writeln!(out, " dyn_call(id, \"{fn_name}\", args)"); + } + } + let _ = writeln!(out, " }}"); + let _ = writeln!(out); +} + +/// Extract the `mize = ...` dependency assignment from a part's Cargo.toml. +/// +/// Looks under `[dependencies]` (and `[dependencies.mize]` table form) and returns +/// a single-line assignment suitable for writing into generated/Cargo.toml, e.g. +/// `mize = { workspace = true }`. +pub fn extract_mize_dependency(cargo_toml: &str) -> Result { + let mut in_deps = false; + let mut in_mize_table = false; + let mut mize_table_fields: Vec = Vec::new(); + + for raw_line in cargo_toml.lines() { + let line = raw_line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + + if line.starts_with('[') && line.ends_with(']') { + if in_mize_table { + break; + } + in_deps = line == "[dependencies]"; + in_mize_table = line == "[dependencies.mize]"; + continue; + } + + if in_mize_table { + mize_table_fields.push(line.to_string()); + continue; + } + + if !in_deps { + continue; + } + + // Inline: mize = ... + if let Some(rest) = line.strip_prefix("mize") { + let rest = rest.trim_start(); + if rest.starts_with('=') { + return Ok(format!("mize {}", rest)); + } + } + } + + if !mize_table_fields.is_empty() { + return Ok(format!("mize = {{ {} }}", mize_table_fields.join(", "))); + } + + Err("no 'mize' dependency found under [dependencies] in part Cargo.toml".to_string()) +} + /// Generate the `Cargo.toml` content for the generated package. -pub fn generate_cargo_toml(package_name: &str) -> String { +/// +/// `mize_dep` is the full assignment line copied from the part Cargo.toml, +/// e.g. `mize = { workspace = true }` or `mize = { path = "../../core" }`. +pub fn generate_cargo_toml(package_name: &str, mize_dep: &str) -> String { format!( r#"[package] name = "{package_name}" @@ -159,9 +478,10 @@ name = "{lib_name}" path = "src/lib.rs" [dependencies] -mize = {{ path = "../../core" }} +{mize_dep} "#, package_name = package_name, lib_name = package_name.replace('-', "_"), + mize_dep = mize_dep.trim(), ) } diff --git a/parts/mize.dev/src/generated.rs b/parts/mize.dev/src/generated.rs index 2ae1a88..969550b 100644 --- a/parts/mize.dev/src/generated.rs +++ b/parts/mize.dev/src/generated.rs @@ -6,8 +6,8 @@ pub struct CliPart { } impl MizePart for CliPart { - fn id(&self) -> MizeId { - self.id.clone() + fn id(&self) -> MizeResult { + Ok(self.id.clone()) } } @@ -15,7 +15,7 @@ impl CliPart { pub fn get(name: &str) -> MizeResult { let mut mize = get_global_mize()?; let part = mize.get_part(name)?; - Ok(CliPart { id: part.id() }) + Ok(CliPart { id: part.id()? }) } pub fn run(&self, cmdline: Vec) -> MizeResult<()> { let cmdline = cmdline.into_item_data(); @@ -34,7 +34,7 @@ impl CliPart { pub fn subcommand MizeResult<()> + Send + Sync + 'static>(&self, subcmd: Command, action: T) -> MizeResult<()> { let mut subcmd_arg = ItemData::new(); subcmd_arg.set_path("_native", subcmd.native_id)?; - let mut action_arg = ItemData::fun(Box::new(move |args: ItemData| { + let action_arg = ItemData::fun(Box::new(move |args: ItemData| { let matches = args.clone().get_path("0")?.native_take_from::()?; action(matches)?; Ok(ItemData::new()) diff --git a/parts/mize.dev/src/lib.rs b/parts/mize.dev/src/lib.rs index 0f7527f..a2f45e3 100644 --- a/parts/mize.dev/src/lib.rs +++ b/parts/mize.dev/src/lib.rs @@ -2,6 +2,7 @@ use std::fs::{create_dir_all, write}; use mize::prelude::*; use cmd_lib::run_cmd as sh; use mize::tracing::info; +use mize::tracing::debug; // a static version of what would be generated. // as we need mize.dev to generate anything. @@ -13,8 +14,7 @@ use generated::*; #[unsafe(no_mangle)] extern "C" fn part_dev() -> MizeResult<()> { - let mut mize = get_global_mize()?; - let mut cli = generated::CliPart::get("cli")?; + let cli = generated::CliPart::get("cli")?; cli.set_command("dev"); cli.subcommand(Command::new("test")?, |_| {println!("hello from test command"); Ok(())})?; @@ -50,11 +50,19 @@ pub fn publish_mize(_ : ArgMatches) -> MizeResult<()> { "x86_64-apple-darwin" => "darwin", _ => "base", }; - sh!(docker build -t mize-build-$docker_image $mize_src/parts/mize.dev/targets/$docker_image)?; - let res = sh!(docker run -it --rm -v $cargo_dir/registry:/usr/local/cargo/registry -v $cargo_dir/git:/usr/local/cargo/git -v $mize_src:/src -v $mize_src/target:/src/target mize-build-$docker_image cargo build --target $target_name --release); + let tmp = std::env::var("TMP").unwrap(); + let mut build_config = ItemData::new(); + build_config.set_path("namespace", "mize.buildtime.ns")?; + std::fs::create_dir_all(&tmp)?; + std::fs::File::create(format!("{tmp}/mize-part-dev-build-config.toml"))?; + std::fs::write(format!("{tmp}/mize-part-dev-build-config.toml"), build_config.to_json()?)?; + sh!(docker build -t mize-build-$docker_image $mize_src/parts/mize.dev/docker/$docker_image)?; + sh!(echo running in container: docker run -it --rm -v "$tmp/mize-part-dev-build-config.toml:/build-config.toml" -e MIZE_BUILD_CONFIG=/build-config.toml -v $cargo_dir/registry:/usr/local/cargo/registry -v $cargo_dir/git:/usr/local/cargo/git -v $mize_src:/src -v $mize_src/target:/src/target mize-build-$docker_image cargo build --target $target_name --release --workspace)?; + let res = sh!(docker run -it --rm -v "$tmp/mize-part-dev-build-config.toml:/build-config.toml" -e MIZE_BUILD_CONFIG=/build-config.toml -v $cargo_dir/registry:/usr/local/cargo/registry -v $cargo_dir/git:/usr/local/cargo/git -v $mize_src:/src -v $mize_src/target:/src/target mize-build-$docker_image cargo build --target $target_name --release); if res.is_err() { info!("build for {target_name} failed..."); } + break; }; @@ -79,11 +87,11 @@ pub fn gen_bindings(_ : ArgMatches) -> MizeResult<()> { // 2. parse the part name and the gen = [...] list let part_name: String = part_data - .get_path("name") + .get_path("id") .ok() .and_then(|v| v.value_string().ok()) .ok_or_else(|| mize_err!("part file must have a 'name' field"))?; - info!("part name: {part_name}"); + println!("part name: {part_name}"); let gen_data = part_data .get_path("gen") @@ -97,7 +105,7 @@ pub fn gen_bindings(_ : ArgMatches) -> MizeResult<()> { let s = v.as_text().ok_or_else(|| mize_err!("'gen' array must contain only strings"))?; gen_parts.push(s.to_owned()); } - info!("parts to generate bindings for: {:?}", gen_parts); + debug!("parts to generate bindings for: {:?}", gen_parts); // 3. enable generate mode and clear any old metadata mize.set_generate_mode(true)?; @@ -122,7 +130,13 @@ pub fn gen_bindings(_ : ArgMatches) -> MizeResult<()> { create_dir_all(&src_dir).map_err(|e| mize_err!("could not create generated/src dir: {e}"))?; let package_name = format!("mize-generated-{part_name}"); - let cargo_toml = codegen::generate_cargo_toml(&package_name); + let part_cargo_path = cwd.join("Cargo.toml"); + let part_cargo = std::fs::read_to_string(&part_cargo_path) + .map_err(|e| mize_err!("could not read part Cargo.toml {}: {e}", part_cargo_path.display()))?; + let mize_dep = codegen::extract_mize_dependency(&part_cargo) + .map_err(|e| mize_err!("{e}"))?; + debug!("using mize dependency from part Cargo.toml: {mize_dep}"); + let cargo_toml = codegen::generate_cargo_toml(&package_name, &mize_dep); write(gen_dir.join("Cargo.toml"), cargo_toml) .map_err(|e| mize_err!("could not write generated/Cargo.toml: {e}"))?; diff --git a/parts/mize.ui/dioxus-components/Cargo.toml b/parts/mize.ui/dioxus-components/Cargo.toml index 80dfebc..2de003f 100644 --- a/parts/mize.ui/dioxus-components/Cargo.toml +++ b/parts/mize.ui/dioxus-components/Cargo.toml @@ -8,10 +8,9 @@ license = "MIT OR Apache-2.0" [dependencies] dioxus = { version = "0.7", default-features = false } dioxus-primitives = { git = "https://github.com/DioxusLabs/components", default-features = false } -dioxus-code = { version = "0.1.0", default-features = false, features = ["macro", "lang-css"] } dioxus-icons = "0.1.0" [features] default = [] web = ["dioxus/web", "dioxus-primitives/web"] -desktop = ["dioxus/desktop"] +desktop = ["dioxus/desktop", "dioxus-primitives/web"] diff --git a/parts/mize.ui/dioxus-components/assets/theme.css b/parts/mize.ui/dioxus-components/assets/theme.css deleted file mode 100644 index ef666aa..0000000 --- a/parts/mize.ui/dioxus-components/assets/theme.css +++ /dev/null @@ -1,44 +0,0 @@ -/* mize UI theme — include once; toggle via html[data-theme="light"|"dark"] */ - -html[data-theme="dark"] { - --dark: initial; - --light: ; -} - -html[data-theme="light"] { - --dark: ; - --light: initial; -} - -@media (prefers-color-scheme: dark) { - :root:not([data-theme]) { - --dark: initial; - --light: ; - } -} - -@media (prefers-color-scheme: light) { - :root:not([data-theme]) { - --dark: ; - --light: initial; - } -} - -:root { - --bg: var(--dark, #171d18) var(--light, #f7f8f4); - --surface: var(--dark, #242d25) var(--light, #ffffff); - --surface-2: var(--dark, #2c362d) var(--light, #eff2ea); - --text: var(--dark, #f2f4ea) var(--light, #20251c); - --text-2: var(--dark, #aab5a4) var(--light, #66705e); - --border: var(--dark, #3a463a) var(--light, #dfe4d9); - --accent: var(--dark, #d7e47d) var(--light, #fec251); - --accent-text: var(--dark, #d7e47d) var(--light, #79500f); - --success: var(--dark, #b9d987) var(--light, #526f32); - --info: var(--dark, #b9e4eb) var(--light, #376777); - --warning: var(--dark, #ffd77f) var(--light, #a66b13); - --danger: var(--dark, #ff9b8e) var(--light, #b94d42); - - /* On-accent fill text: dark ink on light accent, dark surface on dark accent */ - --on-accent: var(--dark, #171d18) var(--light, #79500f); - --focus-ring: var(--accent); -} diff --git a/parts/mize.ui/dioxus-components/src/components/avatar/component.rs b/parts/mize.ui/dioxus-components/src/components/avatar/component.rs index dea6692..83e5b87 100644 --- a/parts/mize.ui/dioxus-components/src/components/avatar/component.rs +++ b/parts/mize.ui/dioxus-components/src/components/avatar/component.rs @@ -3,9 +3,92 @@ use dioxus_primitives::dioxus_attributes::attributes; use dioxus_primitives::avatar::{self, AvatarState}; use dioxus_primitives::merge_attributes; -#[css_module("/src/components/avatar/style.css")] -struct Styles; +const STYLE: &str = r#".dx-avatar { + position: relative; + display: inline-flex; + overflow: hidden; + width: 64px; + height: 64px; + flex-shrink: 0; + align-items: center; + justify-content: center; + color: var(--text); + font-weight: 500; +} + +.dx-avatar-image { + width: 100%; + height: 100%; + aspect-ratio: 1; + object-fit: cover; +} + +.dx-avatar-sm { + width: 2rem; + height: 2rem; + font-size: 0.875rem; +} + +.dx-avatar-md { + width: 2.5rem; + height: 2.5rem; + font-size: 1rem; +} + +.dx-avatar-lg { + width: 3.5rem; + height: 3.5rem; + font-size: 1.5rem; +} + +.dx-avatar-circle { + border-radius: 50%; +} + +.dx-avatar-rounded { + border-radius: 0.375rem; +} + +.dx-avatar[data-state="loading"] { + animation: dx-pulse 1.5s infinite ease-in-out; + background: var(--surface-2); +} + +.dx-avatar[data-state="empty"] { + background: var(--surface-2); +} + +@keyframes dx-pulse { + 0% { + opacity: 1; + } + + 50% { + opacity: 0.7; + } + + 100% { + opacity: 1; + } +} + +.dx-avatar-fallback { + display: flex; + width: 100%; + height: 100%; + align-items: center; + justify-content: center; + background: var(--surface-2); + color: var(--text-2); + font-size: inherit; +} + +.dx-avatar[data-state="error"] .dx-avatar-fallback { + background: var(--surface-2); + color: var(--text-2); +} +"#; #[derive(Clone, Copy, PartialEq, Default)] pub enum AvatarImageSize { #[default] @@ -17,9 +100,9 @@ pub enum AvatarImageSize { impl AvatarImageSize { fn to_class(self) -> &'static str { match self { - AvatarImageSize::Small => Styles::dx_avatar_sm.inner, - AvatarImageSize::Medium => Styles::dx_avatar_md.inner, - AvatarImageSize::Large => Styles::dx_avatar_lg.inner, + AvatarImageSize::Small => "dx-avatar-sm", + AvatarImageSize::Medium => "dx-avatar-md", + AvatarImageSize::Large => "dx-avatar-lg", } } } @@ -34,8 +117,8 @@ pub enum AvatarShape { impl AvatarShape { fn to_class(self) -> &'static str { match self { - AvatarShape::Circle => Styles::dx_avatar_circle.inner, - AvatarShape::Rounded => Styles::dx_avatar_rounded.inner, + AvatarShape::Circle => "dx-avatar-circle", + AvatarShape::Rounded => "dx-avatar-rounded", } } } @@ -73,7 +156,7 @@ pub struct AvatarProps { pub fn Avatar(props: AvatarProps) -> Element { let class = format!( "{} {} {}", - Styles::dx_avatar, + "dx-avatar", props.size.to_class(), props.shape.to_class() ); @@ -83,6 +166,8 @@ pub fn Avatar(props: AvatarProps) -> Element { let merged = merge_attributes(vec![base, props.attributes]); rsx! { + crate::OnceStyle { href: "dioxus-components/avatar", css: STYLE } + avatar::Avatar { on_load: props.on_load, on_error: props.on_error, @@ -110,12 +195,14 @@ pub struct AvatarImageProps { #[component] pub fn AvatarImage(props: AvatarImageProps) -> Element { let base = attributes!(img { - class: Styles::dx_avatar_image, + class: "dx-avatar-image", draggable: "false", }); let merged = merge_attributes(vec![base, props.attributes]); rsx! { + crate::OnceStyle { href: "dioxus-components/avatar", css: STYLE } + avatar::AvatarImage { id: props.id, src: props.src, @@ -136,11 +223,13 @@ pub struct AvatarFallbackProps { #[component] pub fn AvatarFallback(props: AvatarFallbackProps) -> Element { let base = attributes!(span { - class: Styles::dx_avatar_fallback, + class: "dx-avatar-fallback", }); let merged = merge_attributes(vec![base, props.attributes]); rsx! { + crate::OnceStyle { href: "dioxus-components/avatar", css: STYLE } + avatar::AvatarFallback { attributes: merged, {props.children} @@ -187,6 +276,8 @@ pub struct ImageAvatarProps { #[component] pub fn ImageAvatar(props: ImageAvatarProps) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/avatar", css: STYLE } + Avatar { on_load: props.on_load, on_error: props.on_error, diff --git a/parts/mize.ui/dioxus-components/src/components/avatar/style.css b/parts/mize.ui/dioxus-components/src/components/avatar/style.css deleted file mode 100644 index 6448c01..0000000 --- a/parts/mize.ui/dioxus-components/src/components/avatar/style.css +++ /dev/null @@ -1,84 +0,0 @@ -.dx-avatar { - position: relative; - display: inline-flex; - overflow: hidden; - width: 64px; - height: 64px; - flex-shrink: 0; - align-items: center; - justify-content: center; - color: var(--text); - font-weight: 500; -} - -.dx-avatar-image { - width: 100%; - height: 100%; - aspect-ratio: 1; - object-fit: cover; -} - -.dx-avatar-sm { - width: 2rem; - height: 2rem; - font-size: 0.875rem; -} - -.dx-avatar-md { - width: 2.5rem; - height: 2.5rem; - font-size: 1rem; -} - -.dx-avatar-lg { - width: 3.5rem; - height: 3.5rem; - font-size: 1.5rem; -} - -.dx-avatar-circle { - border-radius: 50%; -} - -.dx-avatar-rounded { - border-radius: 0.375rem; -} - -.dx-avatar[data-state="loading"] { - animation: dx-pulse 1.5s infinite ease-in-out; - background: var(--surface-2); -} - -.dx-avatar[data-state="empty"] { - background: var(--surface-2); -} - -@keyframes dx-pulse { - 0% { - opacity: 1; - } - - 50% { - opacity: 0.7; - } - - 100% { - opacity: 1; - } -} - -.dx-avatar-fallback { - display: flex; - width: 100%; - height: 100%; - align-items: center; - justify-content: center; - background: var(--surface-2); - color: var(--text-2); - font-size: inherit; -} - -.dx-avatar[data-state="error"] .dx-avatar-fallback { - background: var(--surface-2); - color: var(--text-2); -} diff --git a/parts/mize.ui/dioxus-components/src/components/badge/component.rs b/parts/mize.ui/dioxus-components/src/components/badge/component.rs index 533555a..47de809 100644 --- a/parts/mize.ui/dioxus-components/src/components/badge/component.rs +++ b/parts/mize.ui/dioxus-components/src/components/badge/component.rs @@ -1,9 +1,45 @@ use dioxus::prelude::*; use dioxus_icons::lucide::BadgeCheck; -#[css_module("/src/components/badge/style.css")] -struct Styles; +const STYLE: &str = r#".dx-badge { + display: inline-flex; + min-width: 20px; + height: 20px; + align-items: center; + justify-content: center; + border-radius: 9999px; + font-size: 11px; + font-weight: 600; + gap: 4px; + line-height: 1; +} + +.dx-badge[padding="true"] { + padding: 0 8px; +} + +.dx-badge[data-style="primary"] { + background-color: var(--accent); + color: var(--on-accent); +} + +.dx-badge[data-style="secondary"] { + background-color: var(--surface-2); + color: var(--text); +} + +.dx-badge[data-style="outline"] { + border: 1px solid var(--border); + background-color: var(--surface); + color: var(--text-2); +} + +.dx-badge[data-style="destructive"] { + background-color: var(--danger); + color: var(--dark, #171d18) var(--light, #ffffff); +} +"#; #[derive(Copy, Clone, PartialEq, Default)] #[non_exhaustive] pub enum BadgeVariant { @@ -42,6 +78,8 @@ pub struct BadgeProps { #[component] pub fn Badge(props: BadgeProps) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/badge", css: STYLE } + BadgeElement { "padding": true, variant: props.variant, @@ -54,8 +92,10 @@ pub fn Badge(props: BadgeProps) -> Element { #[component] fn BadgeElement(props: BadgeProps) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/badge", css: STYLE } + span { - class: Styles::dx_badge, + class: "dx-badge", "data-style": props.variant.class(), ..props.attributes, {props.children} @@ -66,6 +106,8 @@ fn BadgeElement(props: BadgeProps) -> Element { #[component] pub fn VerifiedIcon() -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/badge", css: STYLE } + BadgeCheck { size: "12px", stroke: "var(--text)", diff --git a/parts/mize.ui/dioxus-components/src/components/badge/style.css b/parts/mize.ui/dioxus-components/src/components/badge/style.css deleted file mode 100644 index 1ec9c0b..0000000 --- a/parts/mize.ui/dioxus-components/src/components/badge/style.css +++ /dev/null @@ -1,37 +0,0 @@ -.dx-badge { - display: inline-flex; - min-width: 20px; - height: 20px; - align-items: center; - justify-content: center; - border-radius: 9999px; - font-size: 11px; - font-weight: 600; - gap: 4px; - line-height: 1; -} - -.dx-badge[padding="true"] { - padding: 0 8px; -} - -.dx-badge[data-style="primary"] { - background-color: var(--accent); - color: var(--on-accent); -} - -.dx-badge[data-style="secondary"] { - background-color: var(--surface-2); - color: var(--text); -} - -.dx-badge[data-style="outline"] { - border: 1px solid var(--border); - background-color: var(--surface); - color: var(--text-2); -} - -.dx-badge[data-style="destructive"] { - background-color: var(--danger); - color: var(--dark, #171d18) var(--light, #ffffff); -} diff --git a/parts/mize.ui/dioxus-components/src/components/button/component.rs b/parts/mize.ui/dioxus-components/src/components/button/component.rs index bbf3b9c..8c75e58 100644 --- a/parts/mize.ui/dioxus-components/src/components/button/component.rs +++ b/parts/mize.ui/dioxus-components/src/components/button/component.rs @@ -2,9 +2,203 @@ use dioxus::prelude::*; use dioxus_primitives::dioxus_attributes::attributes; use dioxus_primitives::merge_attributes; -#[css_module("/src/components/button/style.css")] -struct Styles; +const STYLE: &str = r#".dx-button { + display: inline-flex; + box-sizing: border-box; + flex-shrink: 0; + align-items: center; + justify-content: center; + padding: 0; + border: none; + border-radius: 0.375rem; + cursor: pointer; + font-family: inherit; + font-size: 0.875rem; + font-weight: 500; + gap: 0.5rem; + line-height: 1.25rem; + outline: none; + transition-duration: 150ms; + transition-property: background-color, color, box-shadow, border-color, opacity; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + white-space: nowrap; +} + +.dx-button svg { + flex-shrink: 0; + pointer-events: none; +} + +.dx-button svg:not([class*="size-"]) { + width: 1rem; + height: 1rem; +} + +.dx-button[data-size="xs"] { + height: 1.5rem; + padding: 0 0.5rem; + font-size: 0.75rem; + gap: 0.25rem; + line-height: 1rem; +} + +.dx-button[data-size="xs"]:has(> svg) { + padding-inline: 0.375rem; +} + +.dx-button[data-size="xs"] svg:not([class*="size-"]) { + width: 0.75rem; + height: 0.75rem; +} + +.dx-button[data-size="sm"] { + height: 1.875rem; + padding: 0 0.625rem; + gap: 0.375rem; +} + +.dx-button[data-size="sm"]:has(> svg) { + padding-inline: 0.5rem; +} + +.dx-button[data-size="default"] { + height: 2rem; + padding: 0.375rem 1rem; +} + +.dx-button[data-size="default"]:has(> svg) { + padding-inline: 0.75rem; +} + +.dx-button[data-size="lg"] { + height: 2.375rem; + padding: 0 1.25rem; +} + +.dx-button[data-size="lg"]:has(> svg) { + padding-inline: 1rem; +} + +.dx-button[data-size="icon"] { + width: 2rem; + height: 2rem; +} + +.dx-button[data-size="icon"] svg:not([class*="size-"]) { + width: 1rem; + height: 1rem; +} + +.dx-button[data-size="icon-xs"] { + width: 1.5rem; + height: 1.5rem; +} + +.dx-button[data-size="icon-xs"] svg:not([class*="size-"]) { + width: 0.75rem; + height: 0.75rem; +} + +.dx-button[data-size="icon-sm"] { + width: 1.875rem; + height: 1.875rem; +} + +.dx-button[data-size="icon-sm"] svg:not([class*="size-"]) { + width: 1rem; + height: 1rem; +} + +.dx-button[data-size="icon-lg"] { + width: 2.375rem; + height: 2.375rem; +} + +.dx-button[data-size="icon-lg"] svg:not([class*="size-"]) { + width: 1rem; + height: 1rem; +} + +.dx-button:disabled { + opacity: 0.5; + pointer-events: none; +} + +.dx-button[data-style="primary"] { + background-color: var(--accent); + color: var(--on-accent); +} + +.dx-button[data-style="primary"]:not(:disabled):hover { + background-color: color-mix(in oklab, var(--accent) 88%, var(--text)); +} + +.dx-button[data-style="secondary"] { + background-color: var(--surface-2); + color: var(--text); +} + +.dx-button[data-style="secondary"]:not(:disabled):hover { + background-color: color-mix(in oklab, var(--surface-2) 85%, var(--text)); +} + +.dx-button[data-style="ghost"] { + background-color: transparent; + color: var(--text-2); +} + +.dx-button[data-style="ghost"]:not(:disabled):hover { + background-color: var(--surface-2); + color: var(--text); +} + +.dx-button[data-style="outline"] { + border: 1px solid var(--border); + background-color: var(--surface); + color: var(--text); +} + +.dx-button[data-style="outline"]:not(:disabled):hover { + background-color: var(--surface-2); +} + +.dx-button[data-style="destructive"] { + background-color: var(--danger); + color: var(--dark, #171d18) var(--light, #ffffff); +} + +.dx-button[data-style="destructive"]:not(:disabled):hover { + background-color: color-mix(in oklab, var(--danger) 88%, var(--text)); +} + +.dx-button[data-style="destructive"]:focus-visible { + box-shadow: 0 0 0 3px color-mix(in oklab, var(--danger) 40%, transparent); +} + +.dx-button[data-style="link"] { + background-color: transparent; + color: var(--accent-text); + text-decoration: none; + text-underline-offset: 0.25rem; +} + +.dx-button[data-style="link"]:not(:disabled):hover { + text-decoration: underline; +} + +.dx-button:focus-visible { + box-shadow: 0 0 0 3px color-mix(in oklab, var(--focus-ring) 45%, transparent); +} + +.dx-button[aria-invalid="true"] { + border-color: var(--danger); +} + +.dx-button[aria-invalid="true"]:focus-visible { + box-shadow: 0 0 0 3px color-mix(in oklab, var(--danger) 40%, transparent); +} +"#; #[derive(Copy, Clone, PartialEq, Default)] #[non_exhaustive] pub enum ButtonVariant { @@ -73,13 +267,15 @@ pub fn Button( children: Element, ) -> Element { let base = attributes!(button { - class: Styles::dx_button, + class: "dx-button", "data-style": variant.class(), "data-size": size.class(), }); let merged = merge_attributes(vec![base, attributes]); rsx! { + crate::OnceStyle { href: "dioxus-components/button", css: STYLE } + button { onclick: move |event| { if let Some(f) = &onclick { diff --git a/parts/mize.ui/dioxus-components/src/components/button/style.css b/parts/mize.ui/dioxus-components/src/components/button/style.css deleted file mode 100644 index e55021d..0000000 --- a/parts/mize.ui/dioxus-components/src/components/button/style.css +++ /dev/null @@ -1,195 +0,0 @@ -.dx-button { - display: inline-flex; - box-sizing: border-box; - flex-shrink: 0; - align-items: center; - justify-content: center; - padding: 0; - border: none; - border-radius: 0.375rem; - cursor: pointer; - font-family: inherit; - font-size: 0.875rem; - font-weight: 500; - gap: 0.5rem; - line-height: 1.25rem; - outline: none; - transition-duration: 150ms; - transition-property: background-color, color, box-shadow, border-color, opacity; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - white-space: nowrap; -} - -.dx-button svg { - flex-shrink: 0; - pointer-events: none; -} - -.dx-button svg:not([class*="size-"]) { - width: 1rem; - height: 1rem; -} - -.dx-button[data-size="xs"] { - height: 1.5rem; - padding: 0 0.5rem; - font-size: 0.75rem; - gap: 0.25rem; - line-height: 1rem; -} - -.dx-button[data-size="xs"]:has(> svg) { - padding-inline: 0.375rem; -} - -.dx-button[data-size="xs"] svg:not([class*="size-"]) { - width: 0.75rem; - height: 0.75rem; -} - -.dx-button[data-size="sm"] { - height: 1.875rem; - padding: 0 0.625rem; - gap: 0.375rem; -} - -.dx-button[data-size="sm"]:has(> svg) { - padding-inline: 0.5rem; -} - -.dx-button[data-size="default"] { - height: 2rem; - padding: 0.375rem 1rem; -} - -.dx-button[data-size="default"]:has(> svg) { - padding-inline: 0.75rem; -} - -.dx-button[data-size="lg"] { - height: 2.375rem; - padding: 0 1.25rem; -} - -.dx-button[data-size="lg"]:has(> svg) { - padding-inline: 1rem; -} - -.dx-button[data-size="icon"] { - width: 2rem; - height: 2rem; -} - -.dx-button[data-size="icon"] svg:not([class*="size-"]) { - width: 1rem; - height: 1rem; -} - -.dx-button[data-size="icon-xs"] { - width: 1.5rem; - height: 1.5rem; -} - -.dx-button[data-size="icon-xs"] svg:not([class*="size-"]) { - width: 0.75rem; - height: 0.75rem; -} - -.dx-button[data-size="icon-sm"] { - width: 1.875rem; - height: 1.875rem; -} - -.dx-button[data-size="icon-sm"] svg:not([class*="size-"]) { - width: 1rem; - height: 1rem; -} - -.dx-button[data-size="icon-lg"] { - width: 2.375rem; - height: 2.375rem; -} - -.dx-button[data-size="icon-lg"] svg:not([class*="size-"]) { - width: 1rem; - height: 1rem; -} - -.dx-button:disabled { - opacity: 0.5; - pointer-events: none; -} - -.dx-button[data-style="primary"] { - background-color: var(--accent); - color: var(--on-accent); -} - -.dx-button[data-style="primary"]:not(:disabled):hover { - background-color: color-mix(in oklab, var(--accent) 88%, var(--text)); -} - -.dx-button[data-style="secondary"] { - background-color: var(--surface-2); - color: var(--text); -} - -.dx-button[data-style="secondary"]:not(:disabled):hover { - background-color: color-mix(in oklab, var(--surface-2) 85%, var(--text)); -} - -.dx-button[data-style="ghost"] { - background-color: transparent; - color: var(--text-2); -} - -.dx-button[data-style="ghost"]:not(:disabled):hover { - background-color: var(--surface-2); - color: var(--text); -} - -.dx-button[data-style="outline"] { - border: 1px solid var(--border); - background-color: var(--surface); - color: var(--text); -} - -.dx-button[data-style="outline"]:not(:disabled):hover { - background-color: var(--surface-2); -} - -.dx-button[data-style="destructive"] { - background-color: var(--danger); - color: var(--dark, #171d18) var(--light, #ffffff); -} - -.dx-button[data-style="destructive"]:not(:disabled):hover { - background-color: color-mix(in oklab, var(--danger) 88%, var(--text)); -} - -.dx-button[data-style="destructive"]:focus-visible { - box-shadow: 0 0 0 3px color-mix(in oklab, var(--danger) 40%, transparent); -} - -.dx-button[data-style="link"] { - background-color: transparent; - color: var(--accent-text); - text-decoration: none; - text-underline-offset: 0.25rem; -} - -.dx-button[data-style="link"]:not(:disabled):hover { - text-decoration: underline; -} - -.dx-button:focus-visible { - box-shadow: 0 0 0 3px color-mix(in oklab, var(--focus-ring) 45%, transparent); -} - -.dx-button[aria-invalid="true"] { - border-color: var(--danger); -} - -.dx-button[aria-invalid="true"]:focus-visible { - box-shadow: 0 0 0 3px color-mix(in oklab, var(--danger) 40%, transparent); -} diff --git a/parts/mize.ui/dioxus-components/src/components/card/component.rs b/parts/mize.ui/dioxus-components/src/components/card/component.rs index 499e87d..6f8a60d 100644 --- a/parts/mize.ui/dioxus-components/src/components/card/component.rs +++ b/parts/mize.ui/dioxus-components/src/components/card/component.rs @@ -1,16 +1,69 @@ use dioxus::prelude::*; -#[css_module("/src/components/card/style.css")] -struct Styles; +const STYLE: &str = r#".dx-card { + display: flex; + flex-direction: column; + padding: 1rem 0; + border: 1px solid var(--border); + border-radius: 0.5rem; + background-color: var(--surface); + box-shadow: 0 1px 0 rgb(0 0 0 / 8%); + color: var(--text); + gap: 1rem; +} + +.dx-card-header { + display: grid; + align-items: start; + padding: 0 1rem; + gap: 0.375rem; + grid-auto-rows: min-content; + grid-template-rows: auto auto; +} + +.dx-card-header:has([data-slot="card-action"]) { + grid-template-columns: 1fr auto; +} + +.dx-card-title { + font-size: 1rem; + font-weight: 600; + line-height: 1.25; +} + +.dx-card-description { + color: var(--text-2); + font-size: 0.875rem; + line-height: 1.25rem; +} + +.dx-card-action { + grid-column-start: 2; + grid-row: 1 / span 2; + place-self: start end; +} + +.dx-card-content { + padding: 0 1rem; +} + +.dx-card-footer { + display: flex; + align-items: center; + padding: 0 1rem; +} +"#; #[component] pub fn Card( #[props(extends=GlobalAttributes)] attributes: Vec, children: Element, ) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/card", css: STYLE } + div { - class: Styles::dx_card, + class: "dx-card", "data-slot": "card", ..attributes, {children} @@ -24,8 +77,10 @@ pub fn CardHeader( children: Element, ) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/card", css: STYLE } + div { - class: Styles::dx_card_header, + class: "dx-card-header", "data-slot": "card-header", ..attributes, {children} @@ -39,8 +94,10 @@ pub fn CardTitle( children: Element, ) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/card", css: STYLE } + div { - class: Styles::dx_card_title, + class: "dx-card-title", "data-slot": "card-title", ..attributes, {children} @@ -54,8 +111,10 @@ pub fn CardDescription( children: Element, ) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/card", css: STYLE } + div { - class: Styles::dx_card_description, + class: "dx-card-description", "data-slot": "card-description", ..attributes, {children} @@ -69,8 +128,10 @@ pub fn CardAction( children: Element, ) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/card", css: STYLE } + div { - class: Styles::dx_card_action, + class: "dx-card-action", "data-slot": "card-action", ..attributes, {children} @@ -84,8 +145,10 @@ pub fn CardContent( children: Element, ) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/card", css: STYLE } + div { - class: Styles::dx_card_content, + class: "dx-card-content", "data-slot": "card-content", ..attributes, {children} @@ -99,8 +162,10 @@ pub fn CardFooter( children: Element, ) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/card", css: STYLE } + div { - class: Styles::dx_card_footer, + class: "dx-card-footer", "data-slot": "card-footer", ..attributes, {children} diff --git a/parts/mize.ui/dioxus-components/src/components/card/style.css b/parts/mize.ui/dioxus-components/src/components/card/style.css deleted file mode 100644 index 03b3ea3..0000000 --- a/parts/mize.ui/dioxus-components/src/components/card/style.css +++ /dev/null @@ -1,52 +0,0 @@ -.dx-card { - display: flex; - flex-direction: column; - padding: 1rem 0; - border: 1px solid var(--border); - border-radius: 0.5rem; - background-color: var(--surface); - box-shadow: 0 1px 0 rgb(0 0 0 / 8%); - color: var(--text); - gap: 1rem; -} - -.dx-card-header { - display: grid; - align-items: start; - padding: 0 1rem; - gap: 0.375rem; - grid-auto-rows: min-content; - grid-template-rows: auto auto; -} - -.dx-card-header:has([data-slot="card-action"]) { - grid-template-columns: 1fr auto; -} - -.dx-card-title { - font-size: 1rem; - font-weight: 600; - line-height: 1.25; -} - -.dx-card-description { - color: var(--text-2); - font-size: 0.875rem; - line-height: 1.25rem; -} - -.dx-card-action { - grid-column-start: 2; - grid-row: 1 / span 2; - place-self: start end; -} - -.dx-card-content { - padding: 0 1rem; -} - -.dx-card-footer { - display: flex; - align-items: center; - padding: 0 1rem; -} diff --git a/parts/mize.ui/dioxus-components/src/components/checkbox/component.rs b/parts/mize.ui/dioxus-components/src/components/checkbox/component.rs index c6ddb90..e4ebcf2 100644 --- a/parts/mize.ui/dioxus-components/src/components/checkbox/component.rs +++ b/parts/mize.ui/dioxus-components/src/components/checkbox/component.rs @@ -2,14 +2,49 @@ use dioxus::prelude::*; use dioxus_icons::lucide::Check; use dioxus_primitives::checkbox::{self, CheckboxProps}; -#[css_module("/src/components/checkbox/style.css")] -struct Styles; +const STYLE: &str = r#".dx-checkbox { + width: 1.125rem; + height: 1.125rem; + box-sizing: border-box; + padding: 0; + border: none; + border-radius: 0.25rem; + margin: 0; + background-color: var(--surface-2); + box-shadow: inset 0 0 0 1px var(--border); + color: var(--on-accent); + cursor: pointer; +} + +.dx-checkbox-indicator { + display: flex; + align-items: center; + justify-content: center; +} + +.dx-checkbox[data-state="checked"] { + background-color: var(--accent); + box-shadow: none; + color: var(--on-accent); +} + +.dx-checkbox:focus-visible { + box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 45%, transparent); +} + +.dx-checkbox[data-disabled="true"] { + cursor: not-allowed; + opacity: 0.5; +} +"#; #[component] pub fn Checkbox(props: CheckboxProps) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/checkbox", css: STYLE } + checkbox::Checkbox { - class: Styles::dx_checkbox, + class: "dx-checkbox", checked: props.checked, default_checked: props.default_checked, required: props.required, @@ -18,7 +53,7 @@ pub fn Checkbox(props: CheckboxProps) -> Element { value: props.value, on_checked_change: props.on_checked_change, attributes: props.attributes, - checkbox::CheckboxIndicator { class: Styles::dx_checkbox_indicator, + checkbox::CheckboxIndicator { class: "dx-checkbox-indicator", Check { size: "1rem" } } } diff --git a/parts/mize.ui/dioxus-components/src/components/checkbox/style.css b/parts/mize.ui/dioxus-components/src/components/checkbox/style.css deleted file mode 100644 index 6665d57..0000000 --- a/parts/mize.ui/dioxus-components/src/components/checkbox/style.css +++ /dev/null @@ -1,34 +0,0 @@ -.dx-checkbox { - width: 1.125rem; - height: 1.125rem; - box-sizing: border-box; - padding: 0; - border: none; - border-radius: 0.25rem; - margin: 0; - background-color: var(--surface-2); - box-shadow: inset 0 0 0 1px var(--border); - color: var(--on-accent); - cursor: pointer; -} - -.dx-checkbox-indicator { - display: flex; - align-items: center; - justify-content: center; -} - -.dx-checkbox[data-state="checked"] { - background-color: var(--accent); - box-shadow: none; - color: var(--on-accent); -} - -.dx-checkbox:focus-visible { - box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 45%, transparent); -} - -.dx-checkbox[data-disabled="true"] { - cursor: not-allowed; - opacity: 0.5; -} diff --git a/parts/mize.ui/dioxus-components/src/components/control/component.rs b/parts/mize.ui/dioxus-components/src/components/control/component.rs new file mode 100644 index 0000000..1d83fd1 --- /dev/null +++ b/parts/mize.ui/dioxus-components/src/components/control/component.rs @@ -0,0 +1,211 @@ +use dioxus::prelude::*; + +use crate::{Button, ButtonVariant, Dialog, DialogDescription, DialogTitle}; + + +const STYLE: &str = r#".dx-control { + display: inline-flex; + width: 100%; + height: 100%; + min-width: 5.5rem; + min-height: 5.5rem; + box-sizing: border-box; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 0.85rem 0.65rem 0.7rem; + border: 1px solid var(--border); + border-radius: 0.375rem; + background: var(--surface); + box-shadow: 0 4px 16px rgb(0 0 0 / 16%); + color: var(--text); + cursor: pointer; + font-family: inherit; + gap: 0.45rem; + outline: none; + transition: background-color 120ms ease, border-color 120ms ease, box-shadow 120ms ease, + transform 120ms ease; + user-select: none; +} + +.dx-control:hover:not(:disabled):not([data-kind="display"]) { + background: var(--surface-2); + border-color: color-mix(in oklab, var(--accent) 45%, var(--border)); + transform: translateY(-1px); +} + +.dx-control:focus-visible { + box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 40%, transparent), + 0 4px 16px rgb(0 0 0 / 16%); +} + +.dx-control[data-enabled="true"] { + border-color: color-mix(in oklab, var(--accent) 70%, var(--border)); + background: color-mix(in oklab, var(--accent) 16%, var(--surface)); +} + +.dx-control[data-kind="display"] { + cursor: default; +} + +.dx-control:disabled { + cursor: not-allowed; + opacity: 0.55; +} + +.dx-control-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2.25rem; + height: 2.25rem; + border-radius: 0.375rem; + background: var(--surface-2); + color: var(--text); +} + +.dx-control[data-enabled="true"] .dx-control-icon { + background: color-mix(in oklab, var(--accent) 28%, var(--surface-2)); + color: var(--accent-text); +} + +.dx-control-icon svg { + width: 1.25rem; + height: 1.25rem; +} + +.dx-control-name { + color: var(--text); + font-size: 0.78rem; + font-weight: 600; + line-height: 1.2; + text-align: center; +} + +.dx-control-value { + color: var(--text-2); + font-size: 0.7rem; + line-height: 1.2; + text-align: center; +} + +.dx-control-actions { + display: flex; + justify-content: flex-end; + margin-top: 0.75rem; + gap: 0.5rem; +} +"#; +#[derive(Copy, Clone, PartialEq, Eq, Default)] +#[non_exhaustive] +pub enum ControlKind { + /// Click toggles an on/off state (optional confirm). + #[default] + Toggle, + /// Click triggers an action (optional confirm). + Action, + /// Read-only display of a setting/value. + Display, +} + +impl ControlKind { + fn as_str(self) -> &'static str { + match self { + ControlKind::Toggle => "toggle", + ControlKind::Action => "action", + ControlKind::Display => "display", + } + } +} + +#[component] +pub fn Control( + /// Visible label under the icon. + name: String, + #[props(default)] + kind: ControlKind, + /// Toggle enabled state (Toggle kind). + #[props(default)] + enabled: bool, + /// Optional value line (useful for Display, also ok for others). + value: Option, + /// If set, show a confirmation dialog before toggling/acting. + confirm: Option, + /// Fired for Action after confirm (or immediately if no confirm). + onclick: Option>, + /// Fired for Toggle with the new enabled value after confirm (or immediately). + on_enabled_change: Option>, + /// Icon element (e.g. a dioxus-icons lucide component). + children: Element, +) -> Element { + let mut confirm_open = use_signal(|| false); + let needs_confirm = confirm.is_some(); + + let do_commit = move || { + match kind { + ControlKind::Toggle => { + if let Some(cb) = on_enabled_change { + cb.call(!enabled); + } + } + ControlKind::Action => { + if let Some(cb) = onclick { + cb.call(()); + } + } + ControlKind::Display => {} + } + }; + + rsx! { + crate::OnceStyle { href: "dioxus-components/control", css: STYLE } + + button { + class: "dx-control", + "data-slot": "control", + "data-kind": kind.as_str(), + "data-enabled": enabled.to_string(), + r#type: "button", + disabled: kind == ControlKind::Display, + onclick: move |_| { + if kind == ControlKind::Display { + return; + } + if needs_confirm { + confirm_open.set(true); + } else { + do_commit(); + } + }, + span { class: "dx-control-icon", {children} } + span { class: "dx-control-name", "{name}" } + if let Some(val) = &value { + span { class: "dx-control-value", "{val}" } + } + } + + if let Some(msg) = confirm { + Dialog { + open: Some(confirm_open()), + on_open_change: move |open| confirm_open.set(open), + DialogTitle { "Confirm" } + DialogDescription { "{msg}" } + div { class: "dx-control-actions", + Button { + variant: ButtonVariant::Ghost, + onclick: move |_| confirm_open.set(false), + "Cancel" + } + Button { + variant: ButtonVariant::Primary, + onclick: move |_| { + confirm_open.set(false); + do_commit(); + }, + "Confirm" + } + } + } + } + } +} diff --git a/parts/mize.ui/dioxus-components/src/components/control/mod.rs b/parts/mize.ui/dioxus-components/src/components/control/mod.rs new file mode 100644 index 0000000..2590c01 --- /dev/null +++ b/parts/mize.ui/dioxus-components/src/components/control/mod.rs @@ -0,0 +1,2 @@ +mod component; +pub use component::*; diff --git a/parts/mize.ui/dioxus-components/src/components/dialog/component.rs b/parts/mize.ui/dioxus-components/src/components/dialog/component.rs index af64ef4..7cd5a2c 100644 --- a/parts/mize.ui/dioxus-components/src/components/dialog/component.rs +++ b/parts/mize.ui/dioxus-components/src/components/dialog/component.rs @@ -2,19 +2,120 @@ use dioxus::prelude::*; use dioxus_primitives::dialog::{self, DialogDescriptionProps, DialogRootProps, DialogTitleProps}; use dioxus_primitives::{dioxus_attributes::attributes, merge_attributes}; -#[css_module("/src/components/dialog/style.css")] -struct Styles; +const STYLE: &str = r#".dx-dialog-backdrop { + position: fixed; + z-index: 1000; + background: rgb(23 29 24 / 55%); + inset: 0; + opacity: 0; + will-change: opacity; +} + +.dx-dialog-backdrop[data-state="closed"] { + animation: dx-dialog-backdrop-animate-out 150ms ease-in forwards; + pointer-events: none; +} + +@keyframes dx-dialog-backdrop-animate-out { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +.dx-dialog-backdrop[data-state="open"] { + animation: dx-dialog-backdrop-animate-in 150ms ease-out forwards; +} + +@keyframes dx-dialog-backdrop-animate-in { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +.dx-dialog { + position: fixed; + z-index: 1001; + top: 50%; + left: 50%; + display: flex; + width: 100%; + max-width: calc(100% - 2rem); + box-sizing: border-box; + flex-direction: column; + padding: 1.5rem 1.25rem 1.25rem; + border: 1px solid var(--border); + border-radius: 0.5rem; + margin: 0; + background: var(--surface); + box-shadow: 0 8px 24px rgb(0 0 0 / 35%); + color: var(--text); + font-family: inherit; + gap: 0.75rem; + text-align: center; + transform: translate(-50%, -50%); +} + +.dx-dialog-title { + margin: 0; + color: var(--text); + font-size: 1.125rem; + font-weight: 600; +} + +.dx-dialog-description { + margin: 0; + color: var(--text-2); + font-size: 0.875rem; + line-height: 1.4; +} + +@media (width >= 40rem) { + .dx-dialog { + max-width: 28rem; + text-align: left; + } +} + +.dx-dialog-close { + position: absolute; + top: 0.75rem; + right: 0.75rem; + align-self: flex-start; + padding: 0; + border: none; + margin: 0; + background: none; + color: var(--text-2); + cursor: pointer; + font-size: 18px; + line-height: 1; +} + +.dx-dialog-close:hover { + color: var(--text); +} +"#; #[component] pub fn Dialog(props: DialogRootProps) -> Element { let base = attributes!(div { - class: Styles::dx_dialog, + class: "dx-dialog", }); let merged = merge_attributes(vec![base, props.attributes]); rsx! { + crate::OnceStyle { href: "dioxus-components/dialog", css: STYLE } + dialog::DialogRoot { - class: Styles::dx_dialog_backdrop, + class: "dx-dialog-backdrop", id: props.id, is_modal: props.is_modal, open: props.open, @@ -32,11 +133,13 @@ pub fn Dialog(props: DialogRootProps) -> Element { #[component] pub fn DialogTitle(props: DialogTitleProps) -> Element { let base = attributes!(h2 { - class: Styles::dx_dialog_title, + class: "dx-dialog-title", }); let merged = merge_attributes(vec![base, props.attributes]); rsx! { + crate::OnceStyle { href: "dioxus-components/dialog", css: STYLE } + dialog::DialogTitle { id: props.id, attributes: merged, @@ -48,11 +151,13 @@ pub fn DialogTitle(props: DialogTitleProps) -> Element { #[component] pub fn DialogDescription(props: DialogDescriptionProps) -> Element { let base = attributes!(p { - class: Styles::dx_dialog_description, + class: "dx-dialog-description", }); let merged = merge_attributes(vec![base, props.attributes]); rsx! { + crate::OnceStyle { href: "dioxus-components/dialog", css: STYLE } + dialog::DialogDescription { id: props.id, attributes: merged, diff --git a/parts/mize.ui/dioxus-components/src/components/dialog/style.css b/parts/mize.ui/dioxus-components/src/components/dialog/style.css deleted file mode 100644 index f4006f5..0000000 --- a/parts/mize.ui/dioxus-components/src/components/dialog/style.css +++ /dev/null @@ -1,100 +0,0 @@ -.dx-dialog-backdrop { - position: fixed; - z-index: 1000; - background: rgb(23 29 24 / 55%); - inset: 0; - opacity: 0; - will-change: opacity; -} - -.dx-dialog-backdrop[data-state="closed"] { - animation: dx-dialog-backdrop-animate-out 150ms ease-in forwards; - pointer-events: none; -} - -@keyframes dx-dialog-backdrop-animate-out { - 0% { - opacity: 1; - } - - 100% { - opacity: 0; - } -} - -.dx-dialog-backdrop[data-state="open"] { - animation: dx-dialog-backdrop-animate-in 150ms ease-out forwards; -} - -@keyframes dx-dialog-backdrop-animate-in { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -.dx-dialog { - position: fixed; - z-index: 1001; - top: 50%; - left: 50%; - display: flex; - width: 100%; - max-width: calc(100% - 2rem); - box-sizing: border-box; - flex-direction: column; - padding: 1.5rem 1.25rem 1.25rem; - border: 1px solid var(--border); - border-radius: 0.5rem; - margin: 0; - background: var(--surface); - box-shadow: 0 8px 24px rgb(0 0 0 / 35%); - color: var(--text); - font-family: inherit; - gap: 0.75rem; - text-align: center; - transform: translate(-50%, -50%); -} - -.dx-dialog-title { - margin: 0; - color: var(--text); - font-size: 1.125rem; - font-weight: 600; -} - -.dx-dialog-description { - margin: 0; - color: var(--text-2); - font-size: 0.875rem; - line-height: 1.4; -} - -@media (width >= 40rem) { - .dx-dialog { - max-width: 28rem; - text-align: left; - } -} - -.dx-dialog-close { - position: absolute; - top: 0.75rem; - right: 0.75rem; - align-self: flex-start; - padding: 0; - border: none; - margin: 0; - background: none; - color: var(--text-2); - cursor: pointer; - font-size: 18px; - line-height: 1; -} - -.dx-dialog-close:hover { - color: var(--text); -} diff --git a/parts/mize.ui/dioxus-components/src/components/input/component.rs b/parts/mize.ui/dioxus-components/src/components/input/component.rs index 541c307..6f7d61e 100644 --- a/parts/mize.ui/dioxus-components/src/components/input/component.rs +++ b/parts/mize.ui/dioxus-components/src/components/input/component.rs @@ -1,7 +1,46 @@ use dioxus::prelude::*; -#[css_module("/src/components/input/style.css")] -struct Styles; +const STYLE: &str = r#".dx-input { + position: relative; + display: flex; + box-sizing: border-box; + flex-direction: row; + align-items: center; + justify-content: space-between; + padding: 8px 12px; + border: none; + border-radius: 0.375rem; + background-color: var(--surface-2); + box-shadow: inset 0 0 0 1px var(--border); + color: var(--text); + font-family: inherit; + font-size: 0.875rem; + gap: 0.25rem; + outline: none; + transition: background-color 100ms ease-out, box-shadow 100ms ease-out; +} + +.dx-input::placeholder { + color: var(--text-2); +} + +.dx-input:disabled { + color: var(--text-2); + cursor: not-allowed; + opacity: 0.6; +} + +.dx-input:hover:not(:disabled) { + background-color: color-mix(in oklab, var(--surface-2) 90%, var(--text)); +} + +.dx-input:focus-visible { + background-color: var(--surface); + box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 2px color-mix(in oklab, var(--accent) 35%, transparent); + color: var(--text); + outline: none; +} +"#; #[component] pub fn Input( oninput: Option>, @@ -29,8 +68,10 @@ pub fn Input( children: Element, ) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/input", css: STYLE } + input { - class: Styles::dx_input, + class: "dx-input", oninput: move |e| _ = oninput.map(|callback| callback(e)), onchange: move |e| _ = onchange.map(|callback| callback(e)), oninvalid: move |e| _ = oninvalid.map(|callback| callback(e)), diff --git a/parts/mize.ui/dioxus-components/src/components/input/style.css b/parts/mize.ui/dioxus-components/src/components/input/style.css deleted file mode 100644 index dc902ab..0000000 --- a/parts/mize.ui/dioxus-components/src/components/input/style.css +++ /dev/null @@ -1,40 +0,0 @@ -.dx-input { - position: relative; - display: flex; - box-sizing: border-box; - flex-direction: row; - align-items: center; - justify-content: space-between; - padding: 8px 12px; - border: none; - border-radius: 0.375rem; - background-color: var(--surface-2); - box-shadow: inset 0 0 0 1px var(--border); - color: var(--text); - font-family: inherit; - font-size: 0.875rem; - gap: 0.25rem; - outline: none; - transition: background-color 100ms ease-out, box-shadow 100ms ease-out; -} - -.dx-input::placeholder { - color: var(--text-2); -} - -.dx-input:disabled { - color: var(--text-2); - cursor: not-allowed; - opacity: 0.6; -} - -.dx-input:hover:not(:disabled) { - background-color: color-mix(in oklab, var(--surface-2) 90%, var(--text)); -} - -.dx-input:focus-visible { - background-color: var(--surface); - box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 2px color-mix(in oklab, var(--accent) 35%, transparent); - color: var(--text); - outline: none; -} diff --git a/parts/mize.ui/dioxus-components/src/components/label/component.rs b/parts/mize.ui/dioxus-components/src/components/label/component.rs index b3e89b9..48d6070 100644 --- a/parts/mize.ui/dioxus-components/src/components/label/component.rs +++ b/parts/mize.ui/dioxus-components/src/components/label/component.rs @@ -1,13 +1,23 @@ use dioxus::prelude::*; use dioxus_primitives::label::{self, LabelProps}; -#[css_module("/src/components/label/style.css")] -struct Styles; +const STYLE: &str = r#".dx-label { + display: flex; + align-items: center; + color: var(--text-2); + font-size: 0.75rem; + font-weight: 500; + letter-spacing: 0.01em; + line-height: 1.2; +} +"#; #[component] pub fn Label(props: LabelProps) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/label", css: STYLE } + label::Label { - class: Styles::dx_label, + class: "dx-label", html_for: props.html_for, attributes: props.attributes, {props.children} diff --git a/parts/mize.ui/dioxus-components/src/components/label/style.css b/parts/mize.ui/dioxus-components/src/components/label/style.css deleted file mode 100644 index 8452dde..0000000 --- a/parts/mize.ui/dioxus-components/src/components/label/style.css +++ /dev/null @@ -1,9 +0,0 @@ -.dx-label { - display: flex; - align-items: center; - color: var(--text-2); - font-size: 0.75rem; - font-weight: 500; - letter-spacing: 0.01em; - line-height: 1.2; -} diff --git a/parts/mize.ui/dioxus-components/src/components/mod.rs b/parts/mize.ui/dioxus-components/src/components/mod.rs index 224a2e0..c2d7905 100644 --- a/parts/mize.ui/dioxus-components/src/components/mod.rs +++ b/parts/mize.ui/dioxus-components/src/components/mod.rs @@ -3,9 +3,11 @@ pub mod badge; pub mod button; pub mod card; pub mod checkbox; +pub mod control; pub mod dialog; pub mod input; pub mod label; +pub mod prompt; pub mod scroll_area; pub mod separator; pub mod switch; @@ -16,9 +18,11 @@ pub use badge::*; pub use button::*; pub use card::*; pub use checkbox::*; +pub use control::*; pub use dialog::*; pub use input::*; pub use label::*; +pub use prompt::*; pub use scroll_area::*; pub use separator::*; pub use switch::*; diff --git a/parts/mize.ui/dioxus-components/src/components/prompt/component.rs b/parts/mize.ui/dioxus-components/src/components/prompt/component.rs new file mode 100644 index 0000000..287de75 --- /dev/null +++ b/parts/mize.ui/dioxus-components/src/components/prompt/component.rs @@ -0,0 +1,103 @@ +use dioxus::prelude::*; + +const STYLE: &str = r#".dx-prompt { + position: relative; + display: flex; + width: 100%; + box-sizing: border-box; + flex-direction: row; + align-items: center; + padding: 0.4rem 0.75rem; + border: 1px solid var(--border); + border-radius: 0.375rem; + background: var(--surface); + box-shadow: none; + gap: 0.5rem; +} + +.dx-prompt-input { + display: block; + width: 100%; + min-height: 1.5rem; + max-height: 1.5rem; + box-sizing: border-box; + padding: 0; + border: none; + margin: 0; + background: transparent; + color: var(--text); + font-family: inherit; + font-size: 0.875rem; + line-height: 1.5rem; + outline: none; + overflow: hidden; + resize: none; + white-space: nowrap; +} + +.dx-prompt-input::placeholder { + color: var(--text-2); +} +"#; + +#[component] +pub fn Prompt( + /// Controlled value of the prompt text. + #[props(default)] + value: String, + /// Placeholder shown when empty. + #[props(default = "Ask anything…".to_string())] + placeholder: String, + /// Autofocus the textarea when mounted (default true). + #[props(default = true)] + autofocus: bool, + oninput: Option>, + onkeydown: Option>, + #[props(extends = GlobalAttributes)] + attributes: Vec, +) -> Element { + let mut textarea_el = use_signal(|| None::>); + + use_effect(move || { + if !autofocus { + return; + } + if let Some(el) = textarea_el() { + spawn(async move { + let _ = el.set_focus(true).await; + }); + } + }); + + rsx! { + crate::OnceStyle { href: "dioxus-components/prompt", css: STYLE } + + div { + class: "dx-prompt", + "data-slot": "prompt", + ..attributes, + textarea { + class: "dx-prompt-input", + "data-slot": "prompt-input", + value, + placeholder, + rows: 1, + onmounted: move |e| textarea_el.set(Some(e.data())), + oninput: move |e| { + if let Some(cb) = &oninput { + cb.call(e); + } + }, + onkeydown: move |e| { + // Enter does nothing for now (no submit). + if e.key() == Key::Enter { + e.prevent_default(); + } + if let Some(cb) = &onkeydown { + cb.call(e); + } + }, + } + } + } +} diff --git a/parts/mize.ui/dioxus-components/src/components/prompt/mod.rs b/parts/mize.ui/dioxus-components/src/components/prompt/mod.rs new file mode 100644 index 0000000..2590c01 --- /dev/null +++ b/parts/mize.ui/dioxus-components/src/components/prompt/mod.rs @@ -0,0 +1,2 @@ +mod component; +pub use component::*; diff --git a/parts/mize.ui/dioxus-components/src/components/scroll_area/style.css b/parts/mize.ui/dioxus-components/src/components/scroll_area/style.css deleted file mode 100644 index cc50e55..0000000 --- a/parts/mize.ui/dioxus-components/src/components/scroll_area/style.css +++ /dev/null @@ -1 +0,0 @@ -/* Scroll area uses unstyled dioxus-primitives; no extra styles for MVP. */ diff --git a/parts/mize.ui/dioxus-components/src/components/separator/component.rs b/parts/mize.ui/dioxus-components/src/components/separator/component.rs index 3944479..19685ac 100644 --- a/parts/mize.ui/dioxus-components/src/components/separator/component.rs +++ b/parts/mize.ui/dioxus-components/src/components/separator/component.rs @@ -2,17 +2,31 @@ use dioxus::prelude::*; use dioxus_primitives::separator::{self, SeparatorProps}; use dioxus_primitives::{dioxus_attributes::attributes, merge_attributes}; -#[css_module("/src/components/separator/style.css")] -struct Styles; +const STYLE: &str = r#".dx-separator { + background-color: var(--border); +} + +.dx-separator[data-orientation="horizontal"] { + width: 100%; + height: 1px; +} + +.dx-separator[data-orientation="vertical"] { + width: 1px; + height: 100%; +} +"#; #[component] pub fn Separator(props: SeparatorProps) -> Element { let base = attributes!(div { - class: Styles::dx_separator, + class: "dx-separator", }); let merged = merge_attributes(vec![base, props.attributes]); rsx! { + crate::OnceStyle { href: "dioxus-components/separator", css: STYLE } + separator::Separator { horizontal: props.horizontal, decorative: props.decorative, diff --git a/parts/mize.ui/dioxus-components/src/components/separator/style.css b/parts/mize.ui/dioxus-components/src/components/separator/style.css deleted file mode 100644 index 9d59198..0000000 --- a/parts/mize.ui/dioxus-components/src/components/separator/style.css +++ /dev/null @@ -1,13 +0,0 @@ -.dx-separator { - background-color: var(--border); -} - -.dx-separator[data-orientation="horizontal"] { - width: 100%; - height: 1px; -} - -.dx-separator[data-orientation="vertical"] { - width: 1px; - height: 100%; -} diff --git a/parts/mize.ui/dioxus-components/src/components/switch/component.rs b/parts/mize.ui/dioxus-components/src/components/switch/component.rs index fe74182..dc9b2bf 100644 --- a/parts/mize.ui/dioxus-components/src/components/switch/component.rs +++ b/parts/mize.ui/dioxus-components/src/components/switch/component.rs @@ -1,14 +1,56 @@ use dioxus::prelude::*; use dioxus_primitives::switch::{self, SwitchProps}; -#[css_module("/src/components/switch/style.css")] -struct Styles; +const STYLE: &str = r#".dx-switch { + all: unset; + position: relative; + width: 2rem; + height: 1.15rem; + border-radius: 9999px; + background-color: var(--surface-2); + box-shadow: inset 0 0 0 1px var(--border); + cursor: pointer; + transition: background-color 150ms, box-shadow 150ms; +} + +.dx-switch[data-state="checked"] { + background-color: var(--accent); + box-shadow: none; +} + +.dx-switch:focus-visible { + box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 45%, transparent); +} + +.dx-switch-thumb { + display: block; + width: calc(1.15rem - 2px); + height: calc(1.15rem - 2px); + border-radius: 9999px; + background-color: var(--text); + transform: translateX(1px); + transition: transform 150ms, background-color 150ms; + will-change: transform; +} + +.dx-switch[data-state="checked"] .dx-switch-thumb { + background-color: var(--on-accent); + transform: translateX(calc(2rem - 1px - (1.15rem - 2px))); +} + +.dx-switch[data-disabled="true"] { + cursor: not-allowed; + opacity: 0.5; +} +"#; #[component] pub fn Switch(props: SwitchProps) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/switch", css: STYLE } + switch::Switch { - class: Styles::dx_switch, + class: "dx-switch", checked: props.checked, default_checked: props.default_checked, disabled: props.disabled, @@ -17,7 +59,7 @@ pub fn Switch(props: SwitchProps) -> Element { value: props.value, on_checked_change: props.on_checked_change, attributes: props.attributes, - switch::SwitchThumb { class: Styles::dx_switch_thumb } + switch::SwitchThumb { class: "dx-switch-thumb" } } } } diff --git a/parts/mize.ui/dioxus-components/src/components/switch/style.css b/parts/mize.ui/dioxus-components/src/components/switch/style.css deleted file mode 100644 index cbec778..0000000 --- a/parts/mize.ui/dioxus-components/src/components/switch/style.css +++ /dev/null @@ -1,41 +0,0 @@ -.dx-switch { - all: unset; - position: relative; - width: 2rem; - height: 1.15rem; - border-radius: 9999px; - background-color: var(--surface-2); - box-shadow: inset 0 0 0 1px var(--border); - cursor: pointer; - transition: background-color 150ms, box-shadow 150ms; -} - -.dx-switch[data-state="checked"] { - background-color: var(--accent); - box-shadow: none; -} - -.dx-switch:focus-visible { - box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 45%, transparent); -} - -.dx-switch-thumb { - display: block; - width: calc(1.15rem - 2px); - height: calc(1.15rem - 2px); - border-radius: 9999px; - background-color: var(--text); - transform: translateX(1px); - transition: transform 150ms, background-color 150ms; - will-change: transform; -} - -.dx-switch[data-state="checked"] .dx-switch-thumb { - background-color: var(--on-accent); - transform: translateX(calc(2rem - 1px - (1.15rem - 2px))); -} - -.dx-switch[data-disabled="true"] { - cursor: not-allowed; - opacity: 0.5; -} diff --git a/parts/mize.ui/dioxus-components/src/components/textarea/component.rs b/parts/mize.ui/dioxus-components/src/components/textarea/component.rs index 56021b0..4021968 100644 --- a/parts/mize.ui/dioxus-components/src/components/textarea/component.rs +++ b/parts/mize.ui/dioxus-components/src/components/textarea/component.rs @@ -1,8 +1,91 @@ use dioxus::prelude::*; -#[css_module("/src/components/textarea/style.css")] -struct Styles; +const STYLE: &str = r#".dx-textarea { + width: 100%; + min-height: 4rem; + box-sizing: border-box; + padding: 8px 12px; + border: none; + border-radius: 0.375rem; + margin: 0; + appearance: none; + background: none; + color: var(--text); + font-family: inherit; + font-size: 0.875rem; + line-height: 1.5; + outline: none; + resize: vertical; + transition: background-color 100ms ease-out, border-color 100ms ease-out, box-shadow 100ms ease-out; +} + +.dx-textarea:disabled { + color: var(--text-2); + cursor: not-allowed; + opacity: 0.6; +} + +.dx-textarea::placeholder { + color: var(--text-2); +} + +.dx-textarea[data-style="default"] { + background: var(--surface-2); + box-shadow: inset 0 0 0 1px var(--border); +} + +.dx-textarea[data-style="default"]:hover:not(:disabled), +.dx-textarea[data-style="default"]:focus { + background: var(--surface); + color: var(--text); +} + +.dx-textarea[data-style="default"]:focus { + box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 2px color-mix(in oklab, var(--accent) 35%, transparent); +} + +.dx-textarea[data-style="fade"] { + background: var(--surface-2); +} + +.dx-textarea[data-style="fade"]:hover:not(:disabled), +.dx-textarea[data-style="fade"]:focus { + background: var(--surface); + color: var(--text); +} + +.dx-textarea[data-style="outline"] { + border: 1px solid var(--border); + background-color: var(--surface); +} + +.dx-textarea[data-style="outline"]:hover:not(:disabled, :focus) { + border-color: color-mix(in oklab, var(--border) 70%, var(--text)); +} + +.dx-textarea[data-style="outline"]:focus { + border-color: var(--accent); +} + +.dx-textarea[data-style="outline"]:invalid, +.dx-textarea[data-style="outline"][aria-invalid="true"] { + border-color: var(--danger); +} + +.dx-textarea[data-style="ghost"] { + background-color: transparent; +} + +.dx-textarea[data-style="ghost"]:hover:not(:disabled) { + background-color: var(--surface-2); + color: var(--text); +} + +.dx-textarea[data-style="ghost"]:focus { + box-shadow: inset 0 0 0 1px var(--accent); +} +"#; #[derive(Copy, Clone, PartialEq, Default)] #[non_exhaustive] pub enum TextareaVariant { @@ -52,8 +135,10 @@ pub fn Textarea( children: Element, ) -> Element { rsx! { + crate::OnceStyle { href: "dioxus-components/textarea", css: STYLE } + textarea { - class: Styles::dx_textarea, + class: "dx-textarea", "data-slot": "textarea", "data-style": variant.class(), oninput: move |e| _ = oninput.map(|callback| callback(e)), diff --git a/parts/mize.ui/dioxus-components/src/components/textarea/style.css b/parts/mize.ui/dioxus-components/src/components/textarea/style.css deleted file mode 100644 index 665ea36..0000000 --- a/parts/mize.ui/dioxus-components/src/components/textarea/style.css +++ /dev/null @@ -1,84 +0,0 @@ -.dx-textarea { - width: 100%; - min-height: 4rem; - box-sizing: border-box; - padding: 8px 12px; - border: none; - border-radius: 0.375rem; - margin: 0; - appearance: none; - background: none; - color: var(--text); - font-family: inherit; - font-size: 0.875rem; - line-height: 1.5; - outline: none; - resize: vertical; - transition: background-color 100ms ease-out, border-color 100ms ease-out, box-shadow 100ms ease-out; -} - -.dx-textarea:disabled { - color: var(--text-2); - cursor: not-allowed; - opacity: 0.6; -} - -.dx-textarea::placeholder { - color: var(--text-2); -} - -.dx-textarea[data-style="default"] { - background: var(--surface-2); - box-shadow: inset 0 0 0 1px var(--border); -} - -.dx-textarea[data-style="default"]:hover:not(:disabled), -.dx-textarea[data-style="default"]:focus { - background: var(--surface); - color: var(--text); -} - -.dx-textarea[data-style="default"]:focus { - box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 2px color-mix(in oklab, var(--accent) 35%, transparent); -} - -.dx-textarea[data-style="fade"] { - background: var(--surface-2); -} - -.dx-textarea[data-style="fade"]:hover:not(:disabled), -.dx-textarea[data-style="fade"]:focus { - background: var(--surface); - color: var(--text); -} - -.dx-textarea[data-style="outline"] { - border: 1px solid var(--border); - background-color: var(--surface); -} - -.dx-textarea[data-style="outline"]:hover:not(:disabled, :focus) { - border-color: color-mix(in oklab, var(--border) 70%, var(--text)); -} - -.dx-textarea[data-style="outline"]:focus { - border-color: var(--accent); -} - -.dx-textarea[data-style="outline"]:invalid, -.dx-textarea[data-style="outline"][aria-invalid="true"] { - border-color: var(--danger); -} - -.dx-textarea[data-style="ghost"] { - background-color: transparent; -} - -.dx-textarea[data-style="ghost"]:hover:not(:disabled) { - background-color: var(--surface-2); - color: var(--text); -} - -.dx-textarea[data-style="ghost"]:focus { - box-shadow: inset 0 0 0 1px var(--accent); -} diff --git a/parts/mize.ui/dioxus-components/src/lib.rs b/parts/mize.ui/dioxus-components/src/lib.rs index b40cb0b..504890d 100644 --- a/parts/mize.ui/dioxus-components/src/lib.rs +++ b/parts/mize.ui/dioxus-components/src/lib.rs @@ -1,7 +1,8 @@ //! Styled Dioxus UI components using the mize color palette. //! -//! Include [`THEME`] once at the app root (e.g. a stylesheet link), and set -//! `html[data-theme="light"]` or `html[data-theme="dark"]` to switch themes. +//! Include [`THEME_CSS`] once at the app root via `document::Style`, and set +//! `html[data-theme="light"]` or `html[data-theme="dark"]` (or a scoped +//! `data-theme` ancestor) to switch themes. #![allow(non_snake_case)] @@ -10,5 +11,75 @@ use dioxus::prelude::*; pub mod components; pub use components::*; -/// Global theme stylesheet (`assets/theme.css`). Link this once in your app. -pub const THEME: Asset = asset!("/assets/theme.css"); +/// Global theme CSS variables. Inject with `document::Style { {THEME_CSS} }`. +pub const THEME_CSS: &str = r#"/* mize UI theme — include once; toggle via html[data-theme="light"|"dark"] */ + +html[data-theme="dark"] { + --dark: initial; + --light: ; +} + +html[data-theme="light"] { + --dark: ; + --light: initial; +} + +@media (prefers-color-scheme: dark) { + :root:not([data-theme]) { + --dark: initial; + --light: ; + } +} + +@media (prefers-color-scheme: light) { + :root:not([data-theme]) { + --dark: ; + --light: initial; + } +} + +:root { + --bg: var(--dark, #171D18) var(--light, #F7F8F4); + --surface: var(--dark, #242D25) var(--light, #FFFFFF); + --surface-2: var(--dark, #2C362D) var(--light, #EFF2EA); + --text: var(--dark, #F2F4EA) var(--light, #20251C); + --text-2: var(--dark, #AAB5A4) var(--light, #66705E); + --border: var(--dark, #3A463A) var(--light, #DFE4D9); + --accent: var(--dark, #D7E47D) var(--light, #FEC251); + --accent-text: var(--dark, #D7E47D) var(--light, #79500F); + --success: var(--dark, #B9D987) var(--light, #526F32); + --info: var(--dark, #B9E4EB) var(--light, #376777); + --warning: var(--dark, #FFD77F) var(--light, #A66B13); + --danger: var(--dark, #FF9B8E) var(--light, #B94D42); + + /* On-accent fill text: dark ink on light accent, dark surface on dark accent */ + --on-accent: var(--dark, #171D18) var(--light, #79500F); + --focus-ring: var(--accent); +} +"#; + +/// Injects a `