diff --git a/Cargo.lock b/Cargo.lock index cecb464..0dc368d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anyhow" version = "1.0.100" @@ -44,6 +59,12 @@ dependencies = [ "zbus", ] +[[package]] +name = "askama_escape" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df27b8d5ddb458c5fb1bbc1ce172d4a38c614a97d550b0ac89003897fb01de4" + [[package]] name = "async-broadcast" version = "0.7.2" @@ -113,7 +134,7 @@ dependencies = [ "futures-util", "log", "pin-project-lite", - "tungstenite", + "tungstenite 0.27.0", ] [[package]] @@ -158,12 +179,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", + "axum-macros", + "base64", "bytes", "form_urlencoded", "futures-util", "http", "http-body", "http-body-util", + "hyper", + "hyper-util", "itoa", "matchit", "memchr", @@ -175,10 +200,14 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", + "sha1", "sync_wrapper", + "tokio", + "tokio-tungstenite 0.28.0", "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -197,8 +226,49 @@ dependencies = [ "sync_wrapper", "tower-layer", "tower-service", + "tracing", ] +[[package]] +name = "axum-extra" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" +dependencies = [ + "axum", + "axum-core", + "bytes", + "futures-util", + "headers", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "serde_core", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "base16" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27c3610c36aee21ce8ac510e6224498de4228ad772a171ed65643a24693a5a8" + [[package]] name = "base64" version = "0.22.1" @@ -349,6 +419,19 @@ dependencies = [ "encoding_rs", ] +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link 0.2.1", +] + [[package]] name = "ciborium" version = "0.2.2" @@ -693,6 +776,20 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.9.0" @@ -770,14 +867,19 @@ dependencies = [ "dioxus-devtools", "dioxus-document", "dioxus-fullstack", + "dioxus-fullstack-macro", "dioxus-history", "dioxus-hooks", "dioxus-html", + "dioxus-liveview", "dioxus-logger", + "dioxus-server", "dioxus-signals", + "dioxus-ssr", "dioxus-stores", "dioxus-web", "manganis", + "serde", "subsecond", "warnings", ] @@ -919,7 +1021,7 @@ dependencies = [ "tokio", "tracing", "tray-icon", - "tungstenite", + "tungstenite 0.27.0", "webbrowser", "wry", ] @@ -934,12 +1036,14 @@ dependencies = [ "dioxus-core", "dioxus-devtools-types", "dioxus-signals", + "futures-channel", + "futures-util", "serde", "serde_json", "subsecond", "thiserror 2.0.17", "tracing", - "tungstenite", + "tungstenite 0.27.0", ] [[package]] @@ -983,6 +1087,7 @@ dependencies = [ "async-tungstenite", "axum", "axum-core", + "axum-extra", "base64", "bytes", "ciborium", @@ -1007,6 +1112,7 @@ dependencies = [ "http", "http-body", "http-body-util", + "inventory", "js-sys", "mime", "pin-project", @@ -1018,9 +1124,15 @@ dependencies = [ "serde_qs", "serde_urlencoded", "thiserror 2.0.17", + "tokio", + "tokio-stream", + "tokio-tungstenite 0.27.0", "tokio-util", + "tower", + "tower-http", + "tower-layer", "tracing", - "tungstenite", + "tungstenite 0.27.0", "url", "wasm-bindgen", "wasm-bindgen-futures", @@ -1156,6 +1268,34 @@ dependencies = [ "web-sys", ] +[[package]] +name = "dioxus-liveview" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f690466a88cc93d7f87e1735aab9cb4a83c70f452ed344a32559577e80505da4" +dependencies = [ + "axum", + "dioxus-cli-config", + "dioxus-core", + "dioxus-devtools", + "dioxus-document", + "dioxus-history", + "dioxus-html", + "dioxus-interpreter-js", + "futures-channel", + "futures-util", + "generational-box", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "slab", + "thiserror 2.0.17", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", +] + [[package]] name = "dioxus-logger" version = "0.7.2" @@ -1168,6 +1308,42 @@ dependencies = [ "tracing-wasm", ] +[[package]] +name = "dioxus-router" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18282604175f38d8c9291946ad6b34899657e47aef994fbbe6defb501a000f33" +dependencies = [ + "dioxus-cli-config", + "dioxus-core", + "dioxus-core-macro", + "dioxus-fullstack-core", + "dioxus-history", + "dioxus-hooks", + "dioxus-html", + "dioxus-router-macro", + "dioxus-signals", + "percent-encoding", + "rustversion", + "tracing", + "url", +] + +[[package]] +name = "dioxus-router-macro" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47340b339c2c3f042b190f541b7241e2547b2e703f813d34ea24b963330c6757" +dependencies = [ + "base16", + "digest", + "proc-macro2", + "quote", + "sha2", + "slab", + "syn 2.0.111", +] + [[package]] name = "dioxus-rsx" version = "0.7.2" @@ -1181,6 +1357,64 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "dioxus-server" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d608c33c39f032469c6eb59f361dc2724799724d8b3e15c824d1047e664c087" +dependencies = [ + "anyhow", + "async-trait", + "axum", + "base64", + "bytes", + "chrono", + "ciborium", + "dashmap", + "dioxus-cli-config", + "dioxus-core", + "dioxus-core-macro", + "dioxus-devtools", + "dioxus-document", + "dioxus-fullstack-core", + "dioxus-history", + "dioxus-hooks", + "dioxus-html", + "dioxus-interpreter-js", + "dioxus-logger", + "dioxus-router", + "dioxus-signals", + "dioxus-ssr", + "enumset", + "futures", + "futures-channel", + "futures-util", + "generational-box", + "http", + "http-body-util", + "hyper", + "hyper-util", + "inventory", + "lru", + "parking_lot", + "pin-project", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "serde_qs", + "subsecond", + "thiserror 2.0.17", + "tokio", + "tokio-tungstenite 0.27.0", + "tokio-util", + "tower", + "tower-http", + "tracing", + "tracing-futures", + "url", + "walkdir", +] + [[package]] name = "dioxus-signals" version = "0.7.2" @@ -1197,6 +1431,18 @@ dependencies = [ "warnings", ] +[[package]] +name = "dioxus-ssr" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "088efddedd39fc29d007bc91c8a61b25130355149ea5313469f96fb695c5e3ab" +dependencies = [ + "askama_escape", + "dioxus-core", + "dioxus-core-types", + "rustc-hash 2.1.1", +] + [[package]] name = "dioxus-stores" version = "0.7.2" @@ -1232,6 +1478,7 @@ dependencies = [ "dioxus-core-types", "dioxus-devtools", "dioxus-document", + "dioxus-fullstack-core", "dioxus-history", "dioxus-html", "dioxus-interpreter-js", @@ -1310,7 +1557,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.9", + "libloading 0.7.4", ] [[package]] @@ -1529,6 +1776,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1971,21 +2224,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "gloo-storage" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a" -dependencies = [ - "gloo-utils", - "js-sys", - "serde", - "serde_json", - "thiserror 1.0.69", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "gloo-timers" version = "0.3.0" @@ -2074,6 +2312,25 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "2.7.1" @@ -2085,11 +2342,22 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "headers" @@ -2178,6 +2446,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + [[package]] name = "httparse" version = "1.10.1" @@ -2200,9 +2474,11 @@ dependencies = [ "bytes", "futures-channel", "futures-core", + "h2", "http", "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", "pin-utils", @@ -2247,9 +2523,36 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", + "tower-layer", "tower-service", "tracing", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[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]] @@ -2367,7 +2670,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", ] [[package]] @@ -2618,6 +2921,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86" +[[package]] +name = "lru" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96051b46fc183dc9cd4a223960ef37b9af631b55191852a8274bfef064cda20f" +dependencies = [ + "hashbrown 0.16.1", +] + [[package]] name = "lru-slab" version = "0.1.2" @@ -2771,10 +3083,12 @@ name = "mflow" version = "0.1.0" dependencies = [ "dioxus", - "getrandom 0.3.4", - "gloo-storage", + "getrandom 0.2.16", + "gloo-timers", + "once_cell", "serde", "serde_json", + "tokio", ] [[package]] @@ -4390,6 +4704,27 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "system-deps" version = "6.2.2" @@ -4599,6 +4934,7 @@ dependencies = [ "bytes", "libc", "mio", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -4628,6 +4964,42 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489a59b6730eda1b0171fcfda8b121f4bee2b35cba8645ca35c5f7ba3eb736c1" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.27.0", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.28.0", +] + [[package]] name = "tokio-util" version = "0.7.17" @@ -4638,6 +5010,7 @@ dependencies = [ "futures-core", "futures-io", "futures-sink", + "futures-util", "pin-project-lite", "tokio", ] @@ -4730,6 +5103,7 @@ dependencies = [ "tokio", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -4740,14 +5114,24 @@ checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags 2.10.0", "bytes", + "futures-core", "futures-util", "http", "http-body", + "http-body-util", + "http-range-header", + "httpdate", "iri-string", + "mime", + "mime_guess", + "percent-encoding", "pin-project-lite", + "tokio", + "tokio-util", "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -4768,6 +5152,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4793,6 +5178,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-subscriber" version = "0.3.22" @@ -4865,6 +5260,23 @@ dependencies = [ "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.2", + "sha1", + "thiserror 2.0.17", + "utf-8", +] + [[package]] name = "typenum" version = "1.19.0" @@ -5351,8 +5763,8 @@ dependencies = [ "windows-implement", "windows-interface", "windows-link 0.1.3", - "windows-result", - "windows-strings", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -5410,6 +5822,17 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -5419,6 +5842,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -5428,6 +5860,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-sys" version = "0.45.0" diff --git a/Cargo.toml b/Cargo.toml index 2a2ecde..63fc3e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,27 @@ [package] name = "mflow" version = "0.1.0" -authors = ["malxte"] edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -dioxus = { version = "0.7.1", features = [] } +# Version an CLI anpassen (0.6 ist stabil für Fullstack) +dioxus = { version = "0.7.1", features = ["fullstack"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -getrandom = { version = "0.3", features = ["wasm_js"] } +once_cell = "1.19" +# Wichtig: "time" und "sync" Features hinzufügen +tokio = { version = "1", features = ["sync", "time", "rt"] } +gloo-timers = { version = "0.3", features = ["futures"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tokio = { version = "1", features = ["full"] } [target.'cfg(target_arch = "wasm32")'.dependencies] -gloo-storage = "0.3" +getrandom = { version = "0.2", features = ["js"] } [features] default = ["desktop"] -web = ["dioxus/web"] desktop = ["dioxus/desktop"] +web = ["dioxus/web"] mobile = ["dioxus/mobile"] +server = ["dioxus/server"] diff --git a/README.md b/README.md index 81cc3db..ff6cc81 100644 --- a/README.md +++ b/README.md @@ -62,4 +62,4 @@ Die Anwendung ist dann unter `http://localhost:8080` erreichbar. ## 📝 Lizenz -Dieses Projekt wurde erstellt von [malxte]. +Dieses Projekt wurde erstellt von [Bytemalte]. diff --git a/projects.json b/projects.json index 7fc3d39..0637a08 100644 --- a/projects.json +++ b/projects.json @@ -1,6 +1 @@ -[ - { - "name": "Hallo der erste Test!", - "content": "Das ist mein erstes Projekt!" - } -] +[] \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 655bb10..e655279 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,9 +4,11 @@ mod ui; const MAIN_CSS: Asset = asset!("/assets/main.css"); fn main() { + // Erkennt automatisch ob Web (Client) oder Server (Fullstack) dioxus::launch(App); } +#[allow(non_snake_case)] #[component] fn App() -> Element { rsx! { diff --git a/src/ui.rs b/src/ui.rs index 77fa469..5a753fe 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,59 +1,64 @@ use dioxus::prelude::*; use serde::{Deserialize, Serialize}; -#[cfg(not(target_arch = "wasm32"))] -use std::fs; - -#[cfg(target_arch = "wasm32")] -use gloo_storage::{LocalStorage, Storage}; - #[derive(Clone, PartialEq, Serialize, Deserialize, Debug)] -struct Project { - name: String, - content: String, +pub struct Project { + pub name: String, + pub content: String, } -const STORAGE_KEY: &str = "mflow_projects"; +// --- SERVER LOGIK --- +#[cfg(feature = "server")] +static PROJECTS: once_cell::sync::Lazy>> = + once_cell::sync::Lazy::new(|| { + let data = std::fs::read_to_string("projects.json").unwrap_or_else(|_| "[]".to_string()); + std::sync::RwLock::new(serde_json::from_str(&data).unwrap_or_default()) + }); + +#[server] +pub async fn get_projects() -> Result, ServerFnError> { + Ok(PROJECTS.read().unwrap().clone()) +} + +#[server] +pub async fn update_all_projects(new_projects: Vec) -> Result<(), ServerFnError> { + let mut lock = PROJECTS.write().unwrap(); + *lock = new_projects.clone(); + let data = serde_json::to_string_pretty(&*lock)?; + let _ = std::fs::write("projects.json", data); + Ok(()) +} #[component] pub fn Hero() -> Element { - // --- Initiales Laden --- - let mut projects = use_signal(|| { - #[cfg(target_arch = "wasm32")] - { - LocalStorage::get::>(STORAGE_KEY).unwrap_or_default() - } - #[cfg(not(target_arch = "wasm32"))] - { - fs::read_to_string("projects.json") - .ok() - .and_then(|data| serde_json::from_str::>(&data).ok()) - .unwrap_or_default() - } - }); - + let mut projects = use_signal(Vec::::new); let mut selected_index = use_signal(|| None::); + let mut is_typing = use_signal(|| false); + + // Modal-States let mut show_confirm = use_signal(|| false); let mut index_to_delete = use_signal(|| None::); - // --- Automatisches Speichern --- - use_effect(move || { - let current_projects = projects.read(); - - #[cfg(target_arch = "wasm32")] - { - let _ = LocalStorage::set(STORAGE_KEY, &*current_projects); - } - #[cfg(not(target_arch = "wasm32"))] - { - let data = serde_json::to_string_pretty(&*current_projects).unwrap_or_default(); - let _ = fs::write("projects.json", data); + // Echtzeit-Sync (Polling) + use_resource(move || async move { + loop { + if !is_typing() { + if let Ok(p) = get_projects().await { + if p != projects.read().clone() { + projects.set(p); + } + } + } + #[cfg(target_arch = "wasm32")] + gloo_timers::future::TimeoutFuture::new(1000).await; + #[cfg(not(target_arch = "wasm32"))] + tokio::time::sleep(std::time::Duration::from_millis(1000)).await; } }); rsx! { div { id: "hero", - // Sidebar + // SIDEBAR div { id: "sidebar", h2 { "Projekte" } div { class: "project-list", @@ -77,30 +82,38 @@ pub fn Hero() -> Element { } button { id: "add-project", onclick: move |_| { - projects.write().push(Project { name: "Neues Projekt".into(), content: "".into() }); + let mut p = projects.write(); + p.push(Project { name: "Neues Projekt".into(), content: "".into() }); + let current = p.clone(); + spawn(async move { let _ = update_all_projects(current).await; }); }, "+ Projekt hinzufügen" } } - // Editor Bereich + // EDITOR div { id: "open-project", if let Some(idx) = selected_index() { - { - let name = projects.read()[idx].name.clone(); - let content = projects.read()[idx].content.clone(); - rsx! { - input { - class: "title-input", - value: "{name}", - oninput: move |e| projects.write()[idx].name = e.value() - } - textarea { - class: "content-editor", - value: "{content}", - placeholder: "Schreibe hier deine Notizen...", - oninput: move |e| projects.write()[idx].content = e.value() - } + input { + class: "title-input", + value: "{projects.read()[idx].name}", + onfocusin: move |_| is_typing.set(true), + onfocusout: move |_| is_typing.set(false), + oninput: move |e| { + projects.write()[idx].name = e.value(); + let current = projects.read().clone(); + spawn(async move { let _ = update_all_projects(current).await; }); + } + } + textarea { + class: "content-editor", + value: "{projects.read()[idx].content}", + onfocusin: move |_| is_typing.set(true), + onfocusout: move |_| is_typing.set(false), + oninput: move |e| { + projects.write()[idx].content = e.value(); + let current = projects.read().clone(); + spawn(async move { let _ = update_all_projects(current).await; }); } } } else { @@ -108,19 +121,22 @@ pub fn Hero() -> Element { } } - // Bestätigungs-Modal + // DELETE MODAL if show_confirm() { div { class: "modal-overlay", div { class: "modal-box", h3 { "Projekt löschen?" } - p { "Diese Aktion kann nicht rückgängig gemacht werden." } + p { style: "color: #8b949e;", "Diese Aktion kann nicht rückgängig gemacht werden." } div { class: "modal-buttons", button { class: "btn-cancel", onclick: move |_| show_confirm.set(false), "Abbrechen" } button { class: "btn-confirm", onclick: move |_| { if let Some(i) = index_to_delete() { - projects.write().remove(i); + let mut p = projects.write(); + p.remove(i); + let current = p.clone(); + spawn(async move { let _ = update_all_projects(current).await; }); selected_index.set(None); } show_confirm.set(false);