Compare commits
12 Commits
v1.3.0
..
8ff4fa74e4
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ff4fa74e4 | |||
| 6c2305cac9 | |||
| 7a43d5c11f | |||
| 4325280020 | |||
| ec0c6a3487 | |||
| dd8faf8038 | |||
| bd99b4beac | |||
| 2517cd777f | |||
| ea9ad2f8a7 | |||
| 44425723c6 | |||
| 5caa08e145 | |||
| 44959589f8 |
Generated
+130
-93
@@ -24,8 +24,10 @@ dependencies = [
|
|||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-primitives",
|
"dioxus-primitives",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
|
"js-sys",
|
||||||
"prost",
|
"prost",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde-wasm-bindgen",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
"tonic",
|
"tonic",
|
||||||
"tonic-build",
|
"tonic-build",
|
||||||
@@ -79,7 +81,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"log",
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tungstenite",
|
"tungstenite 0.27.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -509,9 +511,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus"
|
name = "dioxus"
|
||||||
version = "0.7.3"
|
version = "0.7.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92b583b48ac77158495e6678fe3a2b5954fc8866fc04cb9695dd146e88bc329d"
|
checksum = "a44c550c06b6785e16258ad620d5b559f5bbcbcc50e3c18c08aa6af2604a4c32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-asset-resolver",
|
"dioxus-asset-resolver",
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
@@ -537,9 +539,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-asset-resolver"
|
name = "dioxus-asset-resolver"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0161af1d3cfc8ff31503ff1b7ee0068c97771fc38d0cc6566e23483142ddf4f"
|
checksum = "c240c4f092024b26e200ecd64723009173cf5bc2e5083c9feb778c077eb5741b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
"http",
|
"http",
|
||||||
@@ -569,18 +571,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-cli-config"
|
name = "dioxus-cli-config"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccd67ab405e1915a47df9769cd5408545d1b559d5c01ce7a0f442caef520d1f3"
|
checksum = "86a13d42c5defcea333bdbae1dc5d64d078acd0fda1d8a1441c37e06be5146e3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-config-macro"
|
name = "dioxus-config-macro"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f040ec7c41aa5428283f56bb0670afba9631bfe3ffd885f4814807f12c8c9d91"
|
checksum = "1ba1d68a05a8a15293ba65d45c7a3263356f3eedf1a3e599440683f3eb014637"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -588,15 +590,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-config-macros"
|
name = "dioxus-config-macros"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "10c41b47b55a433b61f7c12327c85ba650572bacbcc42c342ba2e87a57975264"
|
checksum = "f43f2d511d3c3c439a2fb7f863668b84caf8e0d2440cbfbcbb28521e26ba7f44"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-core"
|
name = "dioxus-core"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b389b0e3cc01c7da292ad9b884b088835fdd1671d45fbd2f737506152b22eef0"
|
checksum = "fb3dd61889e6a09daec93d44db86047fb8e6603beedcf9351b8528582254e075"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"const_format",
|
"const_format",
|
||||||
@@ -616,9 +618,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-core-macro"
|
name = "dioxus-core-macro"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a82d65f0024fc86f01911a16156d280eea583be5a82a3bed85e7e8e4194302d"
|
checksum = "8577c4d9a8cc23423c4d2137319044b03ab940e4b2790dd25f4f06601bd32d9a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case 0.8.0",
|
"convert_case 0.8.0",
|
||||||
"dioxus-rsx",
|
"dioxus-rsx",
|
||||||
@@ -629,15 +631,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-core-types"
|
name = "dioxus-core-types"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bfc4b8cdc440a55c17355542fc2089d97949bba674255d84cac77805e1db8c9f"
|
checksum = "b99d7d199aad72431b549759550002e7d72c8a257eba500dca9fbdb2122de103"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-devtools"
|
name = "dioxus-devtools"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dcf89488bad8fb0f18b9086ee2db01f95f709801c10c68be42691a36378a0f2d"
|
checksum = "d27e7212436a581ce058d7554f1383916bd18a68ebd6015b0b4c2e9ecb0d5535"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
@@ -648,14 +650,14 @@ dependencies = [
|
|||||||
"subsecond",
|
"subsecond",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tungstenite",
|
"tungstenite 0.28.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-devtools-types"
|
name = "dioxus-devtools-types"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6e7381d9d7d0a0f66b9d5082d584853c3d53be21d34007073daca98ddf26fc4d"
|
checksum = "6aa24ed651b97e0b423270bf07a0f1b7dc0e0fa1f1dc26407cd2a118d6bf9de5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -664,9 +666,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-document"
|
name = "dioxus-document"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ba0aeeff26d9d06441f59fd8d7f4f76098ba30ca9728e047c94486161185ceb"
|
checksum = "24685cb51cc6227ea606c49dfe531836f362c49183d3007241afcd8827498401"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
"dioxus-core-macro",
|
"dioxus-core-macro",
|
||||||
@@ -675,7 +677,7 @@ dependencies = [
|
|||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"generational-box",
|
"generational-box",
|
||||||
"lazy-js-bundle 0.7.3",
|
"lazy-js-bundle 0.7.4",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -683,9 +685,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-fullstack"
|
name = "dioxus-fullstack"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7db1f8b70338072ec408b48d09c96559cf071f87847465d8161294197504c498"
|
checksum = "5940c870751b6273a23b7c0e16d80039f45604d68d9b86c91e27b09edeabeb9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@@ -729,7 +731,7 @@ dependencies = [
|
|||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tungstenite",
|
"tungstenite 0.27.0",
|
||||||
"url",
|
"url",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
@@ -740,9 +742,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-fullstack-core"
|
name = "dioxus-fullstack-core"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cda8b152e85121243741b9d5f2a3d8cb3c47a7b2299e902f98b6a7719915b0a2"
|
checksum = "28333274cfc8e5fe547ab04258c2511350c4930a07af9616d365dc4ba7b22d8f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"axum-core",
|
"axum-core",
|
||||||
@@ -768,9 +770,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-fullstack-macro"
|
name = "dioxus-fullstack-macro"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "255104d4a4f278f1a8482fa30536c91d22260c561c954b753e72987df8d65b2e"
|
checksum = "53f7e5a9fa7f657aa519a07aced8b8936f3ae8a246d94855d497d8cce59b9533"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const_format",
|
"const_format",
|
||||||
"convert_case 0.8.0",
|
"convert_case 0.8.0",
|
||||||
@@ -782,9 +784,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-history"
|
name = "dioxus-history"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8d00ba43bfe6e5ca226fef6128f240ca970bea73cac0462416188026360ccdcf"
|
checksum = "010b446322b3f9176476579fa61c7552f0430abbeec418cab543482da6ca4363"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -792,9 +794,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-hooks"
|
name = "dioxus-hooks"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dab2da4f038c33cb38caa37ffc3f5d6dfbc018f05da35b238210a533bb075823"
|
checksum = "09e7a6ba279050cc161e1215c6db0bd15915c9314ec2916d7b22c113a3039536"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
"dioxus-signals",
|
"dioxus-signals",
|
||||||
@@ -808,9 +810,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-html"
|
name = "dioxus-html"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eded5fa6d2e677b7442a93f4228bf3c0ad2597a8bd3292cae50c869d015f3a99"
|
checksum = "f0715e38cc6537aef5b79d0ddc1f4d7a56c2f4debe46b127eee24d8aa5dafd2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -825,16 +827,16 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"generational-box",
|
"generational-box",
|
||||||
"keyboard-types",
|
"keyboard-types",
|
||||||
"lazy-js-bundle 0.7.3",
|
"lazy-js-bundle 0.7.4",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-html-internal-macro"
|
name = "dioxus-html-internal-macro"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "45462ab85fe059a36841508d40545109fd0e25855012d22583a61908eb5cd02a"
|
checksum = "ff6b7918b0908c8719a6165b4e3c362da4fd311fc7cb48720eddd8a45b2ddfc6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case 0.8.0",
|
"convert_case 0.8.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -844,12 +846,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-interpreter-js"
|
name = "dioxus-interpreter-js"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a42a7f73ad32a5054bd8c1014f4ac78cca3b7f6889210ee2b57ea31b33b6d32f"
|
checksum = "a8ce1cf487007f90d0ec4ec87dff111d74ac04fca0918f9dcc4e80dc3b0531b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"lazy-js-bundle 0.7.3",
|
"lazy-js-bundle 0.7.4",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
"sledgehammer_bindgen",
|
"sledgehammer_bindgen",
|
||||||
"sledgehammer_utils",
|
"sledgehammer_utils",
|
||||||
@@ -860,9 +862,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-logger"
|
name = "dioxus-logger"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1eeab114cb009d9e6b85ea10639a18cfc54bb342f3b837770b004c4daeb89c2"
|
checksum = "d4742b16791a71eb4db2d0747f15c50b278b27369b3d93e5a4d6ec2570bcb9bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -887,9 +889,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-router"
|
name = "dioxus-router"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d5b31f9e27231389bf5a117b7074d22d8c58358b484a2558e56fbab20e64ca4"
|
checksum = "ae50f5efa8d6f936c0c3bb85d7a55f6f19290f106290e331d1136d964e832fe6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
@@ -907,9 +909,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-router-macro"
|
name = "dioxus-router-macro"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "838b9b441a95da62b39cae4defd240b5ebb0ec9f2daea1126099e00a838dc86f"
|
checksum = "ae9beca02f6baca4b223256805536dc92e77a1541bb2331723100f66aae79332"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16",
|
"base16",
|
||||||
"digest",
|
"digest",
|
||||||
@@ -922,9 +924,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-rsx"
|
name = "dioxus-rsx"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53128858f0ccca9de54292a4d48409fda1df75fd5012c6243f664042f0225d68"
|
checksum = "344621f6dc435e76fbe272da09988d0118cf35cc2aa88ebb5ae7c1317a36e57c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"proc-macro2-diagnostics",
|
"proc-macro2-diagnostics",
|
||||||
@@ -947,9 +949,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-signals"
|
name = "dioxus-signals"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f48020bc23bc9766e7cce986c0fd6de9af0b8cbfd432652ec6b1094439c1ec6"
|
checksum = "409bf65d243443416650945f22cd6caf2a6bb13ae0347a50ec5852adb1961072"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
@@ -963,9 +965,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-stores"
|
name = "dioxus-stores"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77aaa9ac56d781bb506cf3c0d23bea96b768064b89fe50d3b4d4659cc6bd8058"
|
checksum = "245ec4f84348e5be77451bd204181998b8bc0995b48ff3adb2db0e0ec430dab4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
"dioxus-signals",
|
"dioxus-signals",
|
||||||
@@ -975,9 +977,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-stores-macro"
|
name = "dioxus-stores-macro"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b1a728622e7b63db45774f75e71504335dd4e6115b235bbcff272980499493a"
|
checksum = "dd9da8e9a1cc2d8bff387e0b99f09f2590b71f67d5d73ab343b2cc9d17990d92"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case 0.8.0",
|
"convert_case 0.8.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -987,9 +989,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dioxus-web"
|
name = "dioxus-web"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b33fe739fed4e8143dac222a9153593f8e2451662ce8fc4c9d167a9d6ec0923"
|
checksum = "eac92ef863bc5333440021e8ec3e538a39598c9c960daeaab66ab10ba940b5e0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
"dioxus-core",
|
"dioxus-core",
|
||||||
@@ -1005,7 +1007,7 @@ dependencies = [
|
|||||||
"generational-box",
|
"generational-box",
|
||||||
"gloo-timers",
|
"gloo-timers",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"lazy-js-bundle 0.7.3",
|
"lazy-js-bundle 0.7.4",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
"send_wrapper",
|
"send_wrapper",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1234,9 +1236,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generational-box"
|
name = "generational-box"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cc4ed190b9de8e734d47a70be59b1e7588b9e8e0d0036e332f4c014e8aed1bc5"
|
checksum = "4ede46ff252793f9b6ef752c506ba8600c69d73cad2ef9bbf2e6dee85019a3bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -1669,10 +1671,12 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.91"
|
version = "0.3.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
|
checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"futures-util",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@@ -1694,9 +1698,9 @@ checksum = "e49596223b9d9d4947a14a25c142a6e7d8ab3f27eb3ade269d238bb8b5c267e2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy-js-bundle"
|
name = "lazy-js-bundle"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7b88b715ab1496c6e6b8f5e927be961c4235196121b6ae59bcb51077a21dd36"
|
checksum = "60d7adc10cb9440d17fa67e467febdfc98931338773d11bfee81809af54d0697"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
@@ -1778,21 +1782,25 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "manganis"
|
name = "manganis"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6cce7d688848bf9d034168513b9a2ffbfe5f61df2ff14ae15e6cfc866efdd344"
|
checksum = "492da8d77990281eabe6ded633e7b0cf805c5cf7a023a99abed8811edc872d6f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const-serialize 0.7.2",
|
"const-serialize 0.7.2",
|
||||||
"const-serialize 0.8.0-alpha.0",
|
"const-serialize 0.8.0-alpha.0",
|
||||||
|
"jni",
|
||||||
"manganis-core",
|
"manganis-core",
|
||||||
"manganis-macro",
|
"manganis-macro",
|
||||||
|
"ndk-context",
|
||||||
|
"objc2",
|
||||||
|
"thiserror 2.0.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "manganis-core"
|
name = "manganis-core"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84ce917b978268fe8a7db49e216343ec7c8f471f7e686feb70940d67293f19d4"
|
checksum = "a1b84cc2951f3b119702fab499b9b1aec3f454929c62feca55b895b82c628308"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const-serialize 0.7.2",
|
"const-serialize 0.7.2",
|
||||||
"const-serialize 0.8.0-alpha.0",
|
"const-serialize 0.8.0-alpha.0",
|
||||||
@@ -1804,9 +1812,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "manganis-macro"
|
name = "manganis-macro"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad513e990f7c0bca86aa68659a7a3dc4c705572ed4c22fd6af32ccf261334cc2"
|
checksum = "6d2e60d36758b201b6ebb8a31aff6b013e58924eeb6d3cbf19aea764f51d69e4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dunce",
|
"dunce",
|
||||||
"macro-string",
|
"macro-string",
|
||||||
@@ -1990,6 +1998,21 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
|
||||||
|
dependencies = [
|
||||||
|
"objc2-encode",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-encode"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.3"
|
||||||
@@ -2722,9 +2745,9 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subsecond"
|
name = "subsecond"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8438668e545834d795d04c4335aafc332ce046106521a29f0a5c6501de34187c"
|
checksum = "5dbb9f2928b6654ccc28d4ddfef5213e97ed66afed4907774d049b376c62a838"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -2741,9 +2764,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subsecond-types"
|
name = "subsecond-types"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e72f747606fc19fe81d6c59e491af93ed7dcbcb6aad9d1d18b05129914ec298"
|
checksum = "388bb28e6ddbee717745963b8932d9a6e24a5d3c93350655f733e938de04d81f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -2950,6 +2973,7 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
@@ -3169,6 +3193,23 @@ dependencies = [
|
|||||||
"utf-8",
|
"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",
|
||||||
|
"sha1",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"utf-8",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
@@ -3303,9 +3344,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.114"
|
version = "0.2.118"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e"
|
checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -3316,23 +3357,19 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
version = "0.4.64"
|
version = "0.4.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8"
|
checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
|
||||||
"futures-util",
|
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"once_cell",
|
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.114"
|
version = "0.2.118"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6"
|
checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -3340,9 +3377,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.114"
|
version = "0.2.118"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3"
|
checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -3353,9 +3390,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.114"
|
version = "0.2.118"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16"
|
checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -3375,9 +3412,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.91"
|
version = "0.3.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9"
|
checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ edition = "2024"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus = { version = "0.7.3", features = ["router"] }
|
dioxus = { version = "0.7.5", features = ["router"] }
|
||||||
serde = "1.0.228"
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
serde_repr = "0.1.20"
|
serde_repr = "0.1.20"
|
||||||
tonic = { version = "*", default-features = false, features = [
|
tonic = { version = "*", default-features = false, features = [
|
||||||
"codegen",
|
"codegen",
|
||||||
@@ -15,8 +15,10 @@ tonic = { version = "*", default-features = false, features = [
|
|||||||
] }
|
] }
|
||||||
prost = "0.13"
|
prost = "0.13"
|
||||||
tonic-web-wasm-client = "0.7"
|
tonic-web-wasm-client = "0.7"
|
||||||
web-sys = { version = "0.3.91", features = ["Storage", "Window"] }
|
web-sys = { version = "0.3.91", features = ["Storage", "Window", "Navigator", "CredentialsContainer", "CredentialCreationOptions", "AttestationConveyancePreference", "PublicKeyCredentialCreationOptions", "PublicKeyCredentialRpEntity", "PublicKeyCredentialUserEntity"] }
|
||||||
dioxus-primitives = { git = "https://github.com/DioxusLabs/components", version = "0.0.1", default-features = false }
|
dioxus-primitives = { git = "https://github.com/DioxusLabs/components", version = "0.0.1", default-features = false }
|
||||||
|
serde-wasm-bindgen = "0.6.5"
|
||||||
|
js-sys = "0.3.95"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tonic-build = { version = "*", default-features = false, features = ["prost"] }
|
tonic-build = { version = "*", default-features = false, features = ["prost"] }
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ div[role="menu"] {
|
|||||||
width: auto;
|
width: auto;
|
||||||
outline: none;
|
outline: none;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,11 +113,11 @@ $mediaItemSize: 300px;
|
|||||||
&.placeholder {
|
&.placeholder {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.nsfw img {
|
&.blur img {
|
||||||
filter: blur(20px);
|
filter: blur(20px);
|
||||||
transition: filter 0.25s ease-out;
|
transition: filter 0.25s ease-out;
|
||||||
}
|
}
|
||||||
&.nsfw:hover img {
|
&.blur:hover img {
|
||||||
filter: blur(0px);
|
filter: blur(0px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-4
@@ -3,13 +3,15 @@ use std::env;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>>
|
||||||
|
{
|
||||||
tonic_build::configure()
|
tonic_build::configure()
|
||||||
.build_server(false)
|
.build_server(false)
|
||||||
.build_client(true)
|
.build_client(true)
|
||||||
.compile_protos(
|
.compile_protos(
|
||||||
&[
|
&[
|
||||||
"../AobaServer/Proto/Aoba.proto",
|
"../AobaServer/Proto/Aoba.proto",
|
||||||
|
"../AobaServer/Proto/Account.proto",
|
||||||
"../AobaServer/Proto/Auth.proto",
|
"../AobaServer/Proto/Auth.proto",
|
||||||
"../AobaServer/Proto/Metrics.proto",
|
"../AobaServer/Proto/Metrics.proto",
|
||||||
"../AobaServer/Proto/Types.proto",
|
"../AobaServer/Proto/Types.proto",
|
||||||
@@ -20,15 +22,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn forward_env() {
|
fn forward_env()
|
||||||
|
{
|
||||||
let dest_path = "./src/env.rs";
|
let dest_path = "./src/env.rs";
|
||||||
let mut f = File::create(&dest_path).unwrap();
|
let mut f = File::create(&dest_path).unwrap();
|
||||||
f.write_all(b"// This file is automatically generated by build.rs\n\n")
|
f.write_all(b"// This file is automatically generated by build.rs\n\n")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
for (key, value) in env::vars() {
|
for (key, value) in env::vars()
|
||||||
if key.starts_with("APP_") {
|
{
|
||||||
|
if key.starts_with("APP_")
|
||||||
|
{
|
||||||
f.write_all("#[allow(dead_code)]\n".as_bytes()).unwrap();
|
f.write_all("#[allow(dead_code)]\n".as_bytes()).unwrap();
|
||||||
let line = format!(
|
let line = format!(
|
||||||
"pub const {}: &'static str = \"{}\";\n",
|
"pub const {}: &'static str = \"{}\";\n",
|
||||||
|
|||||||
@@ -1,64 +1,63 @@
|
|||||||
|
use super::props::*;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_primitives::context_menu::{
|
|
||||||
self, ContextMenuContentProps, ContextMenuItemProps, ContextMenuProps, ContextMenuTriggerProps,
|
const CONTEXT_MENU_CSS: Asset = asset!("./style.scss");
|
||||||
};
|
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ContextMenu(props: ContextMenuProps) -> Element {
|
pub fn ContextMenu(props: ContextMenuProps) -> Element
|
||||||
rsx! {
|
{
|
||||||
document::Link { rel: "stylesheet", href: asset!("./style.css") }
|
rsx! {
|
||||||
context_menu::ContextMenu {
|
document::Link { rel: "stylesheet", href: CONTEXT_MENU_CSS }
|
||||||
disabled: props.disabled,
|
{props.children}
|
||||||
open: props.open,
|
}
|
||||||
default_open: props.default_open,
|
|
||||||
on_open_change: props.on_open_change,
|
|
||||||
roving_loop: props.roving_loop,
|
|
||||||
attributes: props.attributes,
|
|
||||||
{props.children}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ContextMenuTrigger(props: ContextMenuTriggerProps) -> Element {
|
pub fn ContextMenuTrigger(props: ContextMenuTriggerProps) -> Element
|
||||||
rsx! {
|
{
|
||||||
context_menu::ContextMenuTrigger {
|
rsx! {
|
||||||
padding: "20px",
|
div{
|
||||||
background: "var(--primary-color)",
|
class: "contextMenuTrigger",
|
||||||
border: "1px dashed var(--primary-color-6)",
|
oncontextmenu: move|e|{
|
||||||
border_radius: ".5rem",
|
|
||||||
cursor: "context-menu",
|
},
|
||||||
user_select: "none",
|
{props.children}
|
||||||
text_align: "center",
|
}
|
||||||
attributes: props.attributes,
|
}
|
||||||
{props.children}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ContextMenuContent(props: ContextMenuContentProps) -> Element {
|
pub fn ContextMenuContent(props: ContextMenuContentProps) -> Element
|
||||||
rsx! {
|
{
|
||||||
context_menu::ContextMenuContent {
|
rsx! {
|
||||||
class: "context-menu-content",
|
div{
|
||||||
id: props.id,
|
class: "contextMenuContent",
|
||||||
attributes: props.attributes,
|
{props.children}
|
||||||
{props.children}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ContextMenuItem(props: ContextMenuItemProps) -> Element {
|
pub fn ContextMenuItem(props: ContextMenuItemProps) -> Element
|
||||||
rsx! {
|
{
|
||||||
context_menu::ContextMenuItem {
|
rsx! {
|
||||||
class: "context-menu-item",
|
div {
|
||||||
disabled: props.disabled,
|
class: "contextMenuItem",
|
||||||
value: props.value,
|
onclick: move |_|{
|
||||||
index: props.index,
|
props.on_select.call(props.value.clone());
|
||||||
on_select: props.on_select,
|
},
|
||||||
attributes: props.attributes,
|
div {
|
||||||
{props.children}
|
class: "content",
|
||||||
}
|
{props.children}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn ContextMenuNestedContent(props: ContextMenuNestedProps) -> Element
|
||||||
|
{
|
||||||
|
rsx! {
|
||||||
|
{props.children}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
mod component;
|
mod component;
|
||||||
pub use component::*;
|
mod props;
|
||||||
|
pub use component::*;
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Props, Clone, PartialEq)]
|
||||||
|
pub struct ContextMenuProps
|
||||||
|
{
|
||||||
|
pub children: Element,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Props, Clone, PartialEq)]
|
||||||
|
pub struct ContextMenuItemProps
|
||||||
|
{
|
||||||
|
pub value: String,
|
||||||
|
pub on_select: EventHandler<String>,
|
||||||
|
pub children: Element,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Props, Clone, PartialEq)]
|
||||||
|
pub struct ContextMenuTriggerProps
|
||||||
|
{
|
||||||
|
pub children: Element,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Props, Clone, PartialEq)]
|
||||||
|
pub struct ContextMenuContentProps
|
||||||
|
{
|
||||||
|
pub children: Element,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Props, Clone, PartialEq)]
|
||||||
|
pub struct ContextMenuNestedProps
|
||||||
|
{
|
||||||
|
pub children: Element,
|
||||||
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
.context-menu-content {
|
|
||||||
z-index: 1000;
|
|
||||||
min-width: 220px;
|
|
||||||
padding: 0.25rem;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
background: var(--dark, var(--primary-color-5))
|
|
||||||
var(--light, var(--primary-color));
|
|
||||||
box-shadow: inset 0 0 0 1px var(--dark, var(--primary-color-7))
|
|
||||||
var(--light, var(--primary-color-6));
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
will-change: transform, opacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu-content[data-state="closed"] {
|
|
||||||
animation: context-menu-animate-out 150ms ease-in forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes context-menu-animate-out {
|
|
||||||
0% {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(1) translateY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.95) translateY(-2px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu-content[data-state="open"] {
|
|
||||||
animation: context-menu-animate-in 150ms ease-out forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes context-menu-animate-in {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.95) translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(1) translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 8px 12px;
|
|
||||||
border-radius: calc(0.5rem - 0.25rem);
|
|
||||||
color: var(--secondary-color-4);
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 14px;
|
|
||||||
outline: none;
|
|
||||||
transition: background-color 100ms ease-out;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu-item[data-disabled="true"] {
|
|
||||||
color: var(--secondary-color-5);
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.context-menu-item:hover:not([data-disabled="true"]),
|
|
||||||
.context-menu-item:focus-visible {
|
|
||||||
background: var(--light, var(--primary-color-4))
|
|
||||||
var(--dark, var(--primary-color-7));
|
|
||||||
color: var(--light, var(--secondary-color-1))
|
|
||||||
var(--dark, var(--secondary-color-4));
|
|
||||||
}
|
|
||||||
@@ -1,46 +1,46 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use tonic::IntoRequest;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
components::MediaItem,
|
components::{MediaItem, MediaItemPlaceHolder},
|
||||||
rpc::{aoba::PageFilter, get_rpc_client},
|
rpc::{
|
||||||
|
aoba::{MediaModel, PageFilter},
|
||||||
|
get_rpc_client,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Props)]
|
#[derive(PartialEq, Clone, Props)]
|
||||||
pub struct MediaGridProps {
|
pub struct MediaGridProps {
|
||||||
pub query: Option<String>,
|
pub query: Signal<String>,
|
||||||
pub max_page: Signal<i32>,
|
pub max_page: Signal<i32>,
|
||||||
pub total_items: Signal<i32>,
|
pub total_items: Signal<i32>,
|
||||||
#[props(default = Some(1))]
|
pub page: Signal<i32>,
|
||||||
pub page: Option<i32>,
|
pub page_size: Signal<i32>,
|
||||||
#[props(default = Some(100))]
|
pub on_page_loaded: Option<EventHandler<PaginationInfo>>,
|
||||||
pub page_size: Option<i32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoRequest<PageFilter> for MediaGridProps {
|
pub struct PaginationInfo {
|
||||||
fn into_request(self) -> tonic::Request<PageFilter> {
|
pub total_pages: i32,
|
||||||
let f: PageFilter = self.into();
|
pub total_items: i32,
|
||||||
f.into_request()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<PageFilter> for MediaGridProps {
|
|
||||||
fn into(self) -> PageFilter {
|
|
||||||
PageFilter {
|
|
||||||
page: self.page,
|
|
||||||
page_size: self.page_size,
|
|
||||||
query: self.query,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn MediaGrid(mut props: MediaGridProps) -> Element {
|
pub fn MediaGrid(props: MediaGridProps) -> Element {
|
||||||
|
let mut error_display = use_signal(|| {
|
||||||
|
rsx! {}
|
||||||
|
});
|
||||||
|
let mut items = use_signal::<Option<Vec<MediaModel>>>(|| None);
|
||||||
let media_result = use_resource(use_reactive!(|(props)| async move {
|
let media_result = use_resource(use_reactive!(|(props)| async move {
|
||||||
|
items.set(None);
|
||||||
let mut client = get_rpc_client();
|
let mut client = get_rpc_client();
|
||||||
let result = client.list_media(props.into_request()).await;
|
let request = PageFilter {
|
||||||
|
page_size: Some(props.page_size.cloned()),
|
||||||
|
page: Some(props.page.cloned()),
|
||||||
|
query: Some(props.query.cloned()),
|
||||||
|
};
|
||||||
|
let result = client.list_media(request).await;
|
||||||
if let Ok(items) = result {
|
if let Ok(items) = result {
|
||||||
let res = items.into_inner();
|
let res = items.into_inner();
|
||||||
|
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
} else {
|
} else {
|
||||||
let err = result.err().unwrap();
|
let err = result.err().unwrap();
|
||||||
@@ -49,42 +49,63 @@ pub fn MediaGrid(mut props: MediaGridProps) -> Element {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
match media_result.cloned() {
|
use_effect(move || match media_result() {
|
||||||
Some(value) => match value {
|
Some(value) => match value {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
let pagination = result.pagination.unwrap();
|
if let Some(pagination) = result.pagination {
|
||||||
let total_pages = pagination.total_pages;
|
let total_pages = pagination.total_pages;
|
||||||
let total_items = pagination.total_items;
|
let total_items = pagination.total_items;
|
||||||
props.max_page.set(total_pages.max(1));
|
if let Some(handler) = props.on_page_loaded {
|
||||||
props.total_items.set(total_items.max(1));
|
handler.call(PaginationInfo {
|
||||||
return rsx! {
|
total_pages,
|
||||||
div {
|
total_items,
|
||||||
class: "mediaGrid",
|
});
|
||||||
// oncontextmenu: oncontext,
|
|
||||||
{result.items.iter().map(|itm| rsx!{
|
|
||||||
MediaItem {
|
|
||||||
item: itm.clone()
|
|
||||||
}
|
|
||||||
})},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Err(msg) => rsx! {
|
|
||||||
div {
|
|
||||||
class: "mediaGrid",
|
|
||||||
div {
|
|
||||||
"Failed to load results: {msg}"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
items.set(Some(result.items));
|
||||||
},
|
error_display.set(rsx! {});
|
||||||
None => rsx! {
|
|
||||||
div{
|
|
||||||
class: "mediaGrid",
|
|
||||||
{(0..50).map(|_| rsx!{
|
|
||||||
MediaItem { }
|
|
||||||
})}
|
|
||||||
}
|
}
|
||||||
|
Err(msg) => error_display.set(rsx! {
|
||||||
|
div{
|
||||||
|
"Failed to load results: {msg}"
|
||||||
|
}
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
|
_ => {}
|
||||||
|
});
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: "mediaGrid",
|
||||||
|
{error_display}
|
||||||
|
{match items(){
|
||||||
|
Some(itms) => rsx!{MediaList { items: itms }},
|
||||||
|
None => rsx!{PlaceholderGrid { count: props.page_size.cloned() as usize }}
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn PlaceholderGrid(count: usize) -> Element {
|
||||||
|
rsx! {
|
||||||
|
div{
|
||||||
|
class: "mediaGrid",
|
||||||
|
{(0..count).map(|_| rsx!{
|
||||||
|
MediaItemPlaceHolder { }
|
||||||
|
})}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn MediaList(items: Vec<MediaModel>) -> Element {
|
||||||
|
rsx! {
|
||||||
|
{items.iter().enumerate().map(|(index, itm)| rsx!{
|
||||||
|
MediaItem {
|
||||||
|
item: itm.clone(),
|
||||||
|
index
|
||||||
|
}
|
||||||
|
})}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,180 +5,191 @@ use web_sys::window;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
HOST,
|
HOST,
|
||||||
route::Route,
|
|
||||||
rpc::{
|
rpc::{
|
||||||
aoba::{Id, MediaClass, MediaModel, SetMediaClassRequest},
|
aoba::{Id, MediaModel, SetMediaClassRequest},
|
||||||
get_rpc_client,
|
get_rpc_client,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub struct MediaClassChangeEvent
|
||||||
|
{
|
||||||
|
pub index: usize,
|
||||||
|
pub class: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Props)]
|
#[derive(PartialEq, Clone, Props)]
|
||||||
pub struct MediaItemProps
|
pub struct MediaItemProps
|
||||||
{
|
{
|
||||||
pub item: Option<MediaModel>,
|
pub item: MediaModel,
|
||||||
// pub oncontextmenu: Option<EventHandler<Event<MouseData>>>,
|
pub index: usize,
|
||||||
|
pub on_class_changed: Option<EventHandler<MediaClassChangeEvent>>,
|
||||||
|
pub on_deleted: Option<EventHandler<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn MediaItem(props: MediaItemProps) -> Element
|
pub fn MediaItem(props: MediaItemProps) -> Element
|
||||||
{
|
{
|
||||||
let mut class_signal = use_signal(|| "");
|
let item = props.item;
|
||||||
if let Some(item) = props.item
|
let mtype = item.media_type().as_str_name();
|
||||||
|
let filename = item.file_name;
|
||||||
|
let id = item.id.unwrap().value;
|
||||||
|
let thumb = item.thumb_url;
|
||||||
|
let class = item.class;
|
||||||
|
let mut class_signal = use_signal(|| match class
|
||||||
{
|
{
|
||||||
let mtype = item.media_type().as_str_name();
|
1 => "blur",
|
||||||
let filename = item.file_name;
|
2 => "secret",
|
||||||
let id = item.id.unwrap().value;
|
_ => "",
|
||||||
let thumb = item.thumb_url;
|
});
|
||||||
let class = item.class;
|
let url = item.media_url;
|
||||||
let url = item.media_url;
|
let download = format!("{HOST}{url}");
|
||||||
let download = format!("{HOST}{url}");
|
|
||||||
|
|
||||||
match class
|
return rsx! {
|
||||||
{
|
ContextMenu{
|
||||||
1 => class_signal.set("nsfw"),
|
ContextMenuTrigger{
|
||||||
2 => class_signal.set("secret"),
|
a {
|
||||||
_ => class_signal.set(""),
|
class: "mediaItem {class_signal()}",
|
||||||
};
|
href: "{HOST}{url}",
|
||||||
|
target: "_blank",
|
||||||
return rsx! {
|
"data-id" : id.clone(),
|
||||||
ContextMenu{
|
img { src: "{HOST}{thumb}" }
|
||||||
ContextMenuTrigger{
|
span { class: "info",
|
||||||
a {
|
span { class: "name", "{filename}" }
|
||||||
class: "mediaItem {class_signal()}",
|
span { class: "details",
|
||||||
href: "{HOST}{url}",
|
span { "{mtype}" }
|
||||||
target: "_blank",
|
span { "{item.view_count}" }
|
||||||
"data-id" : id.clone(),
|
|
||||||
img { src: "{HOST}{thumb}" }
|
|
||||||
span { class: "info",
|
|
||||||
span { class: "name", "{filename}" }
|
|
||||||
span { class: "details",
|
|
||||||
span { "{mtype}" }
|
|
||||||
span { "{item.view_count}" }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
ContextMenuContent{
|
},
|
||||||
ContextMenuItem {
|
ContextMenuContent{
|
||||||
index: 0 as usize,
|
ContextMenuItem {
|
||||||
value: id.clone(),
|
index: 0 as usize,
|
||||||
on_select: move |id: String|{
|
value: id.clone(),
|
||||||
window().expect("Failed to get window")
|
on_select: move |id: String|{
|
||||||
.location().set_href(&format!("/media/{}", id))
|
window().expect("Failed to get window")
|
||||||
.expect("Failed to open Url");
|
.location().set_href(&format!("/media/{}", id))
|
||||||
},
|
.expect("Failed to open Url");
|
||||||
div{
|
|
||||||
class: "contextItem",
|
|
||||||
div{
|
|
||||||
class: "label",
|
|
||||||
"Details"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ContextMenuItem {
|
div{
|
||||||
index: 1 as usize,
|
class: "contextItem",
|
||||||
value: "{download}",
|
|
||||||
on_select: move |url: String|{
|
|
||||||
window().expect("Failed to get window").open_with_url_and_target(&url, "_blank").expect("Failed to open url");
|
|
||||||
},
|
|
||||||
div{
|
div{
|
||||||
class: "contextItem",
|
class: "label",
|
||||||
div{
|
"Details"
|
||||||
class: "label",
|
|
||||||
"Download"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
if class != 0 {
|
|
||||||
rsx!{ContextMenuItem {
|
|
||||||
index: 2 as usize,
|
|
||||||
value: "{id}",
|
|
||||||
on_select: async |id: String|{
|
|
||||||
_ = set_class(id, 0).await;
|
|
||||||
},
|
|
||||||
div{
|
|
||||||
class: "contextItem",
|
|
||||||
div{
|
|
||||||
class: "label",
|
|
||||||
"Mark Standard"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
}else{
|
|
||||||
rsx!{}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
},
|
||||||
if class != 1 {
|
ContextMenuItem {
|
||||||
rsx!{ContextMenuItem {
|
index: 1 as usize,
|
||||||
index: 2 as usize,
|
value: "{download}",
|
||||||
value: "{id}",
|
on_select: move |url: String|{
|
||||||
on_select: async |id: String|{
|
window().expect("Failed to get window").open_with_url_and_target(&url, "_blank").expect("Failed to open url");
|
||||||
_ = set_class(id, 1).await;
|
|
||||||
},
|
|
||||||
div{
|
|
||||||
class: "contextItem",
|
|
||||||
div{
|
|
||||||
class: "label",
|
|
||||||
"Mark NSFW"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
}else{
|
|
||||||
rsx!{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
if class != 1 {
|
|
||||||
rsx!{ContextMenuItem {
|
|
||||||
index: 2 as usize,
|
|
||||||
value: "{id}",
|
|
||||||
on_select: async |id: String|{
|
|
||||||
_ = set_class(id, 2).await;
|
|
||||||
},
|
|
||||||
div{
|
|
||||||
class: "contextItem",
|
|
||||||
div{
|
|
||||||
class: "label",
|
|
||||||
"Mark Secret"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
}else{
|
|
||||||
rsx!{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ContextMenuItem {
|
|
||||||
index: 2 as usize,
|
|
||||||
value: "",
|
|
||||||
div{
|
|
||||||
class: "contextItem",
|
|
||||||
div{
|
|
||||||
class: "label",
|
|
||||||
"Delete"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
div{
|
||||||
|
class: "contextItem",
|
||||||
|
div{
|
||||||
|
class: "label",
|
||||||
|
"Download"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if class_signal() != "" {
|
||||||
|
rsx!{ContextMenuItem {
|
||||||
|
index: 2 as usize,
|
||||||
|
value: "{id}",
|
||||||
|
on_select: move |id: String|{
|
||||||
|
spawn(async move {
|
||||||
|
if let Ok(_) = set_class(id, 0).await{
|
||||||
|
class_signal.set("");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
div{
|
||||||
|
class: "contextItem",
|
||||||
|
div{
|
||||||
|
class: "label",
|
||||||
|
"Mark Standard"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}else{rsx!{}}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if class_signal() != "blur" {
|
||||||
|
rsx!{ContextMenuItem {
|
||||||
|
index: 2 as usize,
|
||||||
|
value: "{id}",
|
||||||
|
on_select: move |id: String|{
|
||||||
|
spawn(async move {
|
||||||
|
if let Ok(_) = set_class(id, 1).await{
|
||||||
|
class_signal.set("blur");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
div{
|
||||||
|
class: "contextItem",
|
||||||
|
div{
|
||||||
|
class: "label",
|
||||||
|
"Mark NSFW"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}else{rsx!{}}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if class_signal() != "secret" {
|
||||||
|
rsx!{ContextMenuItem {
|
||||||
|
index: 2 as usize,
|
||||||
|
value: "{id}",
|
||||||
|
on_select: move |id: String|{
|
||||||
|
spawn(async move {
|
||||||
|
if let Ok(_) = set_class(id, 2).await{
|
||||||
|
class_signal.set("secret");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
div{
|
||||||
|
class: "contextItem",
|
||||||
|
div{
|
||||||
|
class: "label",
|
||||||
|
"Mark Secret"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}else{rsx!{}}
|
||||||
|
}
|
||||||
|
ContextMenuItem {
|
||||||
|
index: 2 as usize,
|
||||||
|
value: "",
|
||||||
|
div{
|
||||||
|
class: "contextItem",
|
||||||
|
div{
|
||||||
|
class: "label",
|
||||||
|
"Delete"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn MediaItemPlaceHolder() -> Element
|
||||||
|
{
|
||||||
|
return rsx! {
|
||||||
|
div { class: "mediaItem placeholder",
|
||||||
|
img { },
|
||||||
|
span { class: "info",
|
||||||
|
span { class: "name" }
|
||||||
|
span { class: "details",
|
||||||
|
span { }
|
||||||
|
span { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
};
|
||||||
else
|
|
||||||
{
|
|
||||||
return rsx! {
|
|
||||||
div { class: "mediaItem placeholder",
|
|
||||||
img { },
|
|
||||||
span { class: "info",
|
|
||||||
span { class: "name" }
|
|
||||||
span { class: "details",
|
|
||||||
span { }
|
|
||||||
span { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_class(id: String, class: i32) -> Result<Response<()>, Status>
|
async fn set_class(id: String, class: i32) -> Result<Response<()>, Status>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
pub mod basic;
|
pub mod basic;
|
||||||
// mod context_menu;
|
mod context_menu;
|
||||||
mod icons;
|
mod icons;
|
||||||
mod media_grid;
|
mod media_grid;
|
||||||
mod media_item;
|
mod media_item;
|
||||||
@@ -9,7 +9,7 @@ mod notif;
|
|||||||
mod pagination;
|
mod pagination;
|
||||||
mod passkey;
|
mod passkey;
|
||||||
mod search;
|
mod search;
|
||||||
// pub use context_menu::*;
|
pub use context_menu::*;
|
||||||
pub use media_grid::*;
|
pub use media_grid::*;
|
||||||
pub use media_item::*;
|
pub use media_item::*;
|
||||||
pub use metrics_token::*;
|
pub use metrics_token::*;
|
||||||
@@ -18,4 +18,4 @@ pub use notif::*;
|
|||||||
pub use pagination::*;
|
pub use pagination::*;
|
||||||
pub use passkey::*;
|
pub use passkey::*;
|
||||||
pub use search::*;
|
pub use search::*;
|
||||||
pub mod radio_group;
|
pub mod radio_group;
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ const NAV_CSS: Asset = asset!("/assets/style/nav.scss");
|
|||||||
const NAV_ICON: Asset = asset!("/assets/favicon.ico");
|
const NAV_ICON: Asset = asset!("/assets/favicon.ico");
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Navbar() -> Element {
|
pub fn Navbar() -> Element
|
||||||
|
{
|
||||||
rsx! {
|
rsx! {
|
||||||
document::Link { rel: "stylesheet", href: NAV_CSS }
|
document::Link { rel: "stylesheet", href: NAV_CSS }
|
||||||
nav {
|
nav {
|
||||||
@@ -19,17 +20,19 @@ pub fn Navbar() -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn MainNaviagation() -> Element {
|
pub fn MainNaviagation() -> Element
|
||||||
|
{
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "mainNav",
|
div { class: "mainNav",
|
||||||
Link { class: "navItem", to: Route::Home { }, "Home" }
|
Link { class: "navItem", to: Route::Home { page: None, q: None }, "Home" }
|
||||||
Link { class: "navItem", to: Route::Settings {}, "Settings" }
|
Link { class: "navItem", to: Route::Settings {}, "Settings" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Branding() -> Element {
|
pub fn Branding() -> Element
|
||||||
|
{
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "branding",
|
div { class: "branding",
|
||||||
img { src: NAV_ICON, alt: "Aoba" }
|
img { src: NAV_ICON, alt: "Aoba" }
|
||||||
@@ -38,14 +41,16 @@ pub fn Branding() -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Widgets() -> Element {
|
pub fn Widgets() -> Element
|
||||||
|
{
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "widgets" }
|
div { class: "widgets" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Utils() -> Element {
|
pub fn Utils() -> Element
|
||||||
|
{
|
||||||
let mut auth_context = use_context::<AuthContext>();
|
let mut auth_context = use_context::<AuthContext>();
|
||||||
let version = APP_VERSION;
|
let version = APP_VERSION;
|
||||||
rsx! {
|
rsx! {
|
||||||
|
|||||||
@@ -2,8 +2,12 @@ use dioxus::prelude::*;
|
|||||||
use web_sys::window;
|
use web_sys::window;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Pagination(page: Signal<i32>, max_page: Signal<i32>, item_count: Signal<i32>) -> Element
|
pub fn Pagination(
|
||||||
{
|
page: Signal<i32>,
|
||||||
|
max_page: Signal<i32>,
|
||||||
|
item_count: Signal<i32>,
|
||||||
|
on_page_change: EventHandler<i32>,
|
||||||
|
) -> Element {
|
||||||
let cur_page_val = page.cloned();
|
let cur_page_val = page.cloned();
|
||||||
let max_page_val = max_page.cloned();
|
let max_page_val = max_page.cloned();
|
||||||
let item_count_val = item_count.cloned();
|
let item_count_val = item_count.cloned();
|
||||||
@@ -12,16 +16,16 @@ pub fn Pagination(page: Signal<i32>, max_page: Signal<i32>, item_count: Signal<i
|
|||||||
class: "pagination",
|
class: "pagination",
|
||||||
a {
|
a {
|
||||||
onclick: move|_| {
|
onclick: move|_| {
|
||||||
page.set(1);
|
on_page_change.call(1);
|
||||||
on_page_change();
|
scroll_document();
|
||||||
},
|
},
|
||||||
"First"
|
"First"
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
onclick: move|_| {
|
onclick: move|_| {
|
||||||
let p = (cur_page_val - 1).max(1);
|
let p = (cur_page_val - 1).max(1);
|
||||||
page.set(p);
|
on_page_change.call(p);
|
||||||
on_page_change();
|
scroll_document();
|
||||||
},
|
},
|
||||||
"Prev"
|
"Prev"
|
||||||
}
|
}
|
||||||
@@ -29,15 +33,15 @@ pub fn Pagination(page: Signal<i32>, max_page: Signal<i32>, item_count: Signal<i
|
|||||||
a {
|
a {
|
||||||
onclick: move|_| {
|
onclick: move|_| {
|
||||||
let p = (cur_page_val + 1).min(max_page_val);
|
let p = (cur_page_val + 1).min(max_page_val);
|
||||||
page.set(p);
|
on_page_change.call(p);
|
||||||
on_page_change();
|
scroll_document();
|
||||||
},
|
},
|
||||||
"Next"
|
"Next"
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
onclick: move|_| {
|
onclick: move|_| {
|
||||||
page.set(max_page_val);
|
on_page_change.call(max_page_val);
|
||||||
on_page_change();
|
scroll_document();
|
||||||
},
|
},
|
||||||
"Last"
|
"Last"
|
||||||
}
|
}
|
||||||
@@ -45,8 +49,7 @@ pub fn Pagination(page: Signal<i32>, max_page: Signal<i32>, item_count: Signal<i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_page_change()
|
fn scroll_document() {
|
||||||
{
|
|
||||||
let window = window().expect("Failed to get window");
|
let window = window().expect("Failed to get window");
|
||||||
let document = window.document().expect("Failed to get document");
|
let document = window.document().expect("Failed to get document");
|
||||||
document
|
document
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
use js_sys::{Uint8Array, wasm_bindgen::JsValue};
|
||||||
|
use web_sys::{
|
||||||
|
CredentialCreationOptions, PublicKeyCredentialCreationOptions, PublicKeyCredentialRpEntity,
|
||||||
|
PublicKeyCredentialUserEntity, window,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::components::basic::Button;
|
use crate::{components::basic::Button, rpc::aoba::PasskeyCredentialCreateOptions};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn PasskeyRegistrationButton() -> Element
|
pub fn PasskeyRegistrationButton() -> Element
|
||||||
@@ -8,16 +13,58 @@ pub fn PasskeyRegistrationButton() -> Element
|
|||||||
rsx! {
|
rsx! {
|
||||||
Button{
|
Button{
|
||||||
text: "Register Passkey",
|
text: "Register Passkey",
|
||||||
onclick: move |e| {
|
onclick: move |_| {
|
||||||
|
start_passkey_registration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_passkey_registration() {}
|
fn start_passkey_registration()
|
||||||
|
{
|
||||||
|
create_credential(todo!());
|
||||||
|
}
|
||||||
|
|
||||||
fn create_credential() {}
|
fn create_credential(req_opts: PasskeyCredentialCreateOptions)
|
||||||
|
{
|
||||||
|
let window = window().expect("Window does not exist");
|
||||||
|
let credentaials = window.navigator().credentials();
|
||||||
|
|
||||||
|
let opts = opts_from_rpc(req_opts);
|
||||||
|
|
||||||
|
let result = credentaials.create_with_options(&opts);
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opts_from_rpc(rpc_opts: PasskeyCredentialCreateOptions) -> CredentialCreationOptions
|
||||||
|
{
|
||||||
|
let opt_user = &rpc_opts.user.expect("user is missing");
|
||||||
|
let opt_rp = &rpc_opts.rp.expect("rp is missing");
|
||||||
|
let opts = CredentialCreationOptions::new();
|
||||||
|
let rp = PublicKeyCredentialRpEntity::new(&opt_rp.name);
|
||||||
|
rp.set_id(&opt_rp.id);
|
||||||
|
|
||||||
|
let user = PublicKeyCredentialUserEntity::new_with_u8_array(
|
||||||
|
&opt_user.name,
|
||||||
|
&opt_user.display_name,
|
||||||
|
&to_u8_array(&opt_user.id),
|
||||||
|
);
|
||||||
|
let pub_key_opts = PublicKeyCredentialCreationOptions::new_with_u8_array(
|
||||||
|
&to_u8_array(&rpc_opts.challenge),
|
||||||
|
&JsValue::undefined(),
|
||||||
|
&rp,
|
||||||
|
&user,
|
||||||
|
);
|
||||||
|
//pub_key_opts.set_exclude_credentials(val);
|
||||||
|
opts.set_public_key(&pub_key_opts);
|
||||||
|
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_u8_array(value: &String) -> Uint8Array
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn PasskeyLoginButton() -> Element
|
pub fn PasskeyLoginButton() -> Element
|
||||||
|
|||||||
@@ -1,14 +1,24 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Search(query: Signal<String>, page: Signal<i32>) -> Element {
|
pub fn Search(query: String, oninput: Option<EventHandler<String>>, onchange: Option<EventHandler<String>>) -> Element
|
||||||
|
{
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "searchBar",
|
div { class: "searchBar",
|
||||||
input {
|
input {
|
||||||
r#type: "search",
|
r#type: "search",
|
||||||
placeholder: "Search Files",
|
placeholder: "Search Files",
|
||||||
value: query,
|
value: query,
|
||||||
oninput: move |event| {query.set(event.value()); page.set(1);},
|
oninput: move |event| {
|
||||||
|
if let Some(handler) = oninput {
|
||||||
|
handler.call(event.value());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onchange: move |event|{
|
||||||
|
if let Some(handler) = onchange {
|
||||||
|
handler.call(event.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-4
@@ -8,7 +8,7 @@ pub mod rpc;
|
|||||||
pub mod views;
|
pub mod views;
|
||||||
|
|
||||||
use contexts::AuthContext;
|
use contexts::AuthContext;
|
||||||
use dioxus::prelude::*;
|
use dioxus::{prelude::*, router::RouterConfig};
|
||||||
use route::Route;
|
use route::Route;
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
@@ -34,7 +34,6 @@ fn main()
|
|||||||
fn App() -> Element
|
fn App() -> Element
|
||||||
{
|
{
|
||||||
use_context_provider(|| AuthContext::new());
|
use_context_provider(|| AuthContext::new());
|
||||||
// use_context_provider(|| ContextMenuRenderer::default());
|
|
||||||
rsx! {
|
rsx! {
|
||||||
document::Link { rel: "icon", href: FAVICON }
|
document::Link { rel: "icon", href: FAVICON }
|
||||||
document::Link { rel: "preconnect", href: "https://fonts.googleapis.com" }
|
document::Link { rel: "preconnect", href: "https://fonts.googleapis.com" }
|
||||||
@@ -46,7 +45,17 @@ fn App() -> Element
|
|||||||
rel: "stylesheet",
|
rel: "stylesheet",
|
||||||
href: "https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap",
|
href: "https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap",
|
||||||
}
|
}
|
||||||
|
Router::<Route> { config: || RouterConfig::default()
|
||||||
Router::<Route> { }
|
.on_update(|state|{
|
||||||
|
match state.current() {
|
||||||
|
Route::Home {page, q} => {
|
||||||
|
info!("Page {}", page.unwrap_or(1));
|
||||||
|
return None;
|
||||||
|
// return Some(NavigationTarget::Internal(Route::Home { page, q }))
|
||||||
|
},
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
layouts::MainLayout,
|
layouts::MainLayout,
|
||||||
views::{Home, HomePaged, Media, Settings},
|
views::{Home, Media, Settings},
|
||||||
};
|
};
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
@@ -9,10 +9,10 @@ use dioxus::prelude::*;
|
|||||||
pub enum Route {
|
pub enum Route {
|
||||||
#[layout(MainLayout)]
|
#[layout(MainLayout)]
|
||||||
|
|
||||||
#[route("/")]
|
|
||||||
Home { },
|
|
||||||
#[route("/?:page&:q")]
|
#[route("/?:page&:q")]
|
||||||
HomePaged { page: i32, q: String },
|
Home { page: Option<i32>, q: Option<String> },
|
||||||
|
// #[route("/")]
|
||||||
|
// Home { },
|
||||||
#[route("/media/:id")]
|
#[route("/media/:id")]
|
||||||
Media { id: String },
|
Media { id: String },
|
||||||
#[route("/settings")]
|
#[route("/settings")]
|
||||||
|
|||||||
+18
-1
@@ -6,7 +6,9 @@ use tonic_web_wasm_client::Client;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
RPC_HOST,
|
RPC_HOST,
|
||||||
rpc::aoba::{auth_rpc_client::AuthRpcClient, metrics_rpc_client::MetricsRpcClient},
|
rpc::aoba::{
|
||||||
|
account_rpc_client::AccountRpcClient, auth_rpc_client::AuthRpcClient, metrics_rpc_client::MetricsRpcClient,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod aoba
|
pub mod aoba
|
||||||
@@ -17,6 +19,7 @@ pub mod aoba
|
|||||||
static RPC_CLIENT: RpcConnection = RpcConnection {
|
static RPC_CLIENT: RpcConnection = RpcConnection {
|
||||||
aoba: RwLock::new(None),
|
aoba: RwLock::new(None),
|
||||||
auth: RwLock::new(None),
|
auth: RwLock::new(None),
|
||||||
|
account: RwLock::new(None),
|
||||||
metrics: RwLock::new(None),
|
metrics: RwLock::new(None),
|
||||||
jwt: RwLock::new(None),
|
jwt: RwLock::new(None),
|
||||||
};
|
};
|
||||||
@@ -26,6 +29,7 @@ pub struct RpcConnection
|
|||||||
{
|
{
|
||||||
aoba: RwLock<Option<AobaRpcClient<InterceptedService<Client, AuthInterceptor>>>>,
|
aoba: RwLock<Option<AobaRpcClient<InterceptedService<Client, AuthInterceptor>>>>,
|
||||||
auth: RwLock<Option<AuthRpcClient<Client>>>,
|
auth: RwLock<Option<AuthRpcClient<Client>>>,
|
||||||
|
account: RwLock<Option<AccountRpcClient<InterceptedService<Client, AuthInterceptor>>>>,
|
||||||
metrics: RwLock<Option<MetricsRpcClient<InterceptedService<Client, AuthInterceptor>>>>,
|
metrics: RwLock<Option<MetricsRpcClient<InterceptedService<Client, AuthInterceptor>>>>,
|
||||||
jwt: RwLock<Option<String>>,
|
jwt: RwLock<Option<String>>,
|
||||||
}
|
}
|
||||||
@@ -38,6 +42,12 @@ impl RpcConnection
|
|||||||
return self.aoba.read().unwrap().clone().unwrap();
|
return self.aoba.read().unwrap().clone().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_account_client(&self) -> AccountRpcClient<InterceptedService<Client, AuthInterceptor>>
|
||||||
|
{
|
||||||
|
self.ensure_client();
|
||||||
|
return self.account.read().unwrap().clone().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_auth_client(&self) -> AuthRpcClient<Client>
|
pub fn get_auth_client(&self) -> AuthRpcClient<Client>
|
||||||
{
|
{
|
||||||
self.ensure_client();
|
self.ensure_client();
|
||||||
@@ -58,6 +68,8 @@ impl RpcConnection
|
|||||||
let aoba_client = AobaRpcClient::with_interceptor(wasm_client.clone(), AuthInterceptor);
|
let aoba_client = AobaRpcClient::with_interceptor(wasm_client.clone(), AuthInterceptor);
|
||||||
*self.aoba.write().unwrap() = Some(aoba_client);
|
*self.aoba.write().unwrap() = Some(aoba_client);
|
||||||
*self.auth.write().unwrap() = Some(AuthRpcClient::new(wasm_client.clone()));
|
*self.auth.write().unwrap() = Some(AuthRpcClient::new(wasm_client.clone()));
|
||||||
|
*self.account.write().unwrap() =
|
||||||
|
Some(AccountRpcClient::with_interceptor(wasm_client.clone(), AuthInterceptor));
|
||||||
*self.metrics.write().unwrap() =
|
*self.metrics.write().unwrap() =
|
||||||
Some(MetricsRpcClient::with_interceptor(wasm_client.clone(), AuthInterceptor));
|
Some(MetricsRpcClient::with_interceptor(wasm_client.clone(), AuthInterceptor));
|
||||||
}
|
}
|
||||||
@@ -90,6 +102,11 @@ pub fn get_auth_rpc_client() -> AuthRpcClient<Client>
|
|||||||
return RPC_CLIENT.get_auth_client();
|
return RPC_CLIENT.get_auth_client();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_account_rpc_client() -> AccountRpcClient<InterceptedService<Client, AuthInterceptor>>
|
||||||
|
{
|
||||||
|
return RPC_CLIENT.get_account_client();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_metrics_rpc_client() -> MetricsRpcClient<InterceptedService<Client, AuthInterceptor>>
|
pub fn get_metrics_rpc_client() -> MetricsRpcClient<InterceptedService<Client, AuthInterceptor>>
|
||||||
{
|
{
|
||||||
return RPC_CLIENT.get_metrics_client();
|
return RPC_CLIENT.get_metrics_client();
|
||||||
|
|||||||
@@ -1,36 +1,60 @@
|
|||||||
use crate::components::{MediaGrid, Pagination, Search};
|
use crate::{
|
||||||
use dioxus::prelude::*;
|
components::{MediaGrid, Pagination, PaginationInfo, Search},
|
||||||
|
route::Route,
|
||||||
|
};
|
||||||
|
use dioxus::{prelude::*, router::RouterConfig};
|
||||||
|
|
||||||
|
// #[component]
|
||||||
|
// pub fn Home() -> Element
|
||||||
|
// {
|
||||||
|
// let query = use_signal(|| "".to_string());
|
||||||
|
// let page = use_signal(|| 1 as i32);
|
||||||
|
// let max_page = use_signal(|| 1 as i32);
|
||||||
|
// let item_count = use_signal(|| 0 as i32);
|
||||||
|
// rsx! {
|
||||||
|
// div {
|
||||||
|
// class: "stickyTop",
|
||||||
|
// Search { query, page },
|
||||||
|
// Pagination { page, max_page, item_count },
|
||||||
|
// }
|
||||||
|
// MediaGrid { query: query.cloned(), page: page.cloned(), max_page, total_items: item_count }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Home() -> Element
|
pub fn Home(page: Option<i32>, q: Option<String>) -> Element
|
||||||
{
|
{
|
||||||
let query = use_signal(|| "".to_string());
|
let mut query = use_signal(|| q.unwrap_or("".to_string()));
|
||||||
let page = use_signal(|| 1 as i32);
|
let mut page = use_signal(|| page.unwrap_or(1));
|
||||||
let max_page = use_signal(|| 1 as i32);
|
let page_size = use_signal::<i32>(|| 100);
|
||||||
let item_count = use_signal(|| 0 as i32);
|
let mut max_page = use_signal(|| 1 as i32);
|
||||||
|
let mut item_count = use_signal(|| 0 as i32);
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
class: "stickyTop",
|
class: "stickyTop",
|
||||||
Search { query, page },
|
Search {
|
||||||
Pagination { page, max_page, item_count },
|
query: query(),
|
||||||
|
oninput: move |q| {
|
||||||
|
query.set(q);
|
||||||
|
page.set(1);
|
||||||
|
},
|
||||||
|
onchange: move |_|{
|
||||||
|
router().push(format!("/?page={}&q={}", page(), query()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Pagination {
|
||||||
|
page, max_page, item_count,
|
||||||
|
on_page_change: move |p|{
|
||||||
|
page.set(p);
|
||||||
|
router().push(format!("/?page={}&q={}", page(), query()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
MediaGrid { query: query, page: page, max_page, total_items: item_count, page_size,
|
||||||
|
on_page_loaded: move |p: PaginationInfo| {
|
||||||
|
max_page.set(p.total_pages);
|
||||||
|
item_count.set(p.total_items);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MediaGrid { query: query.cloned(), page: page.cloned(), max_page, total_items: item_count }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
pub fn HomePaged(page: i32, q: String) -> Element
|
|
||||||
{
|
|
||||||
let query = use_signal(|| q);
|
|
||||||
let page = use_signal(|| page);
|
|
||||||
let max_page = use_signal(|| 1 as i32);
|
|
||||||
let item_count = use_signal(|| 0 as i32);
|
|
||||||
rsx! {
|
|
||||||
div {
|
|
||||||
class: "stickyTop",
|
|
||||||
Search { query, page },
|
|
||||||
Pagination { page, max_page, item_count },
|
|
||||||
}
|
|
||||||
MediaGrid { query: query.cloned(), page: page.cloned(), max_page, total_items: item_count }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use dioxus::prelude::*;
|
|||||||
use tonic::IntoRequest;
|
use tonic::IntoRequest;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{basic::Input, Notif, NotifType},
|
components::{Notif, NotifType, PasskeyLoginButton, basic::Input},
|
||||||
contexts::AuthContext,
|
contexts::AuthContext,
|
||||||
rpc::{aoba::Credentials, get_auth_rpc_client},
|
rpc::{aoba::Credentials, get_auth_rpc_client},
|
||||||
};
|
};
|
||||||
@@ -72,6 +72,7 @@ pub fn Login() -> Element {
|
|||||||
required: true,
|
required: true,
|
||||||
}
|
}
|
||||||
button { onclick: login, "Login!" }
|
button { onclick: login, "Login!" }
|
||||||
|
PasskeyLoginButton {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
use crate::HOST;
|
use crate::HOST;
|
||||||
use crate::components::radio_group::{RadioGroup, RadioItem};
|
|
||||||
use crate::rpc::aoba::SetMediaClassRequest;
|
|
||||||
use crate::rpc::{
|
use crate::rpc::{
|
||||||
aoba::{Id, MediaModel},
|
aoba::{Id, MediaModel},
|
||||||
get_rpc_client,
|
get_rpc_client,
|
||||||
@@ -8,26 +6,20 @@ use crate::rpc::{
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Media(id: String) -> Element
|
pub fn Media(id: String) -> Element {
|
||||||
{
|
|
||||||
let media_result = use_resource(use_reactive!(|(id)| async move {
|
let media_result = use_resource(use_reactive!(|(id)| async move {
|
||||||
let mut client = get_rpc_client();
|
let mut client = get_rpc_client();
|
||||||
let result = client.get_media(Id { value: id.clone() }).await;
|
let result = client.get_media(Id { value: id.clone() }).await;
|
||||||
if let Ok(item) = result
|
if let Ok(item) = result {
|
||||||
{
|
|
||||||
let res = item.into_inner();
|
let res = item.into_inner();
|
||||||
return res.value;
|
return res.value;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return match media_result.cloned().unwrap_or(None)
|
return match media_result.cloned().unwrap_or(None) {
|
||||||
{
|
Some(media) => {
|
||||||
Some(media) =>
|
|
||||||
{
|
|
||||||
return rsx! {MediaPage{media: media}};
|
return rsx! {MediaPage{media: media}};
|
||||||
}
|
}
|
||||||
None => rsx! {"Not Found"},
|
None => rsx! {"Not Found"},
|
||||||
@@ -35,20 +27,18 @@ pub fn Media(id: String) -> Element
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn MediaPage(media: MediaModel) -> Element
|
fn MediaPage(media: MediaModel) -> Element {
|
||||||
{
|
|
||||||
let url = media.thumb_url;
|
let url = media.thumb_url;
|
||||||
let id = media.id.expect("Media has no id").value.clone();
|
// let id = media.id.expect("Media has no id").value.clone();
|
||||||
let cur_class = match media.class
|
let cur_class = use_signal(|| match media.class {
|
||||||
{
|
|
||||||
0 => "Standard",
|
0 => "Standard",
|
||||||
1 => "NSFW",
|
1 => "NSFW",
|
||||||
2 => "Secret",
|
2 => "Secret",
|
||||||
_ => "Unkown",
|
_ => "Unkown",
|
||||||
};
|
});
|
||||||
rsx! {
|
rsx! {
|
||||||
img { src: "{HOST}{url}", }
|
img { src: "{HOST}{url}", }
|
||||||
label { "Media Class: {cur_class}" }
|
label { "Media Class: {cur_class()}" }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,16 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FFMpegCore" Version="5.4.0" />
|
<PackageReference Include="FFMpegCore" Version="5.4.0" />
|
||||||
|
<PackageReference Include="Fido2.Models" Version="4.0.1" />
|
||||||
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0" />
|
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.3" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.5" />
|
||||||
<PackageReference Include="MaybeError" Version="1.2.0" />
|
<PackageReference Include="MaybeError" Version="1.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.3" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.5" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="3.6.0" />
|
<PackageReference Include="MongoDB.Driver" Version="3.7.1" />
|
||||||
<PackageReference Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="3.0.0" />
|
<PackageReference Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="3.0.0" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" />
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.16.0" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.17.0" />
|
||||||
<PackageReference Include="ZLinq" Version="1.5.5" />
|
<PackageReference Include="ZLinq" Version="1.5.6" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Microsoft.IdentityModel.Tokens;
|
using Fido2NetLib.Objects;
|
||||||
|
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
using MongoDB.Bson;
|
using MongoDB.Bson;
|
||||||
using MongoDB.Bson.Serialization.Attributes;
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
@@ -19,6 +21,7 @@ public class User
|
|||||||
public bool IsArgon { get; set; }
|
public bool IsArgon { get; set; }
|
||||||
public ObjectId[] ApiKeys { get; set; } = [];
|
public ObjectId[] ApiKeys { get; set; } = [];
|
||||||
public List<ObjectId> RegTokens { get; set; } = [];
|
public List<ObjectId> RegTokens { get; set; } = [];
|
||||||
|
public List<PublicKeyCredentialDescriptor> CredentialDescriptors { get; set; } = [];
|
||||||
|
|
||||||
public ClaimsIdentity GetIdentity()
|
public ClaimsIdentity GetIdentity()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using AobaCore.Models;
|
using AobaCore.Models;
|
||||||
|
|
||||||
|
using Fido2NetLib.Objects;
|
||||||
|
|
||||||
using Isopoh.Cryptography.Argon2;
|
using Isopoh.Cryptography.Argon2;
|
||||||
|
|
||||||
using MongoDB.Bson;
|
using MongoDB.Bson;
|
||||||
@@ -54,13 +56,18 @@ public class AccountsService(IMongoDatabase db)
|
|||||||
/* Get the salt */
|
/* Get the salt */
|
||||||
byte[] salt = new byte[16];
|
byte[] salt = new byte[16];
|
||||||
Array.Copy(hashBytes, 0, salt, 0, 16);
|
Array.Copy(hashBytes, 0, salt, 0, 16);
|
||||||
/* Compute the hash on the password the user entered */
|
|
||||||
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000, HashAlgorithmName.SHA1);
|
var hash= Rfc2898DeriveBytes.Pbkdf2(password, salt, 10000, HashAlgorithmName.SHA1, 20);
|
||||||
byte[] hash = pbkdf2.GetBytes(20);
|
|
||||||
/* Compare the results */
|
/* Compare the results */
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
if (hashBytes[i + 16] != hash[i])
|
if (hashBytes[i + 16] != hash[i])
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<PublicKeyCredentialDescriptor>> GetPublicKeyCredentialDescriptorsAsync(ObjectId id, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var creds = await _users.Find(u => u.Id == id).Project(u => u.CredentialDescriptors).FirstOrDefaultAsync(cancellationToken);
|
||||||
|
return creds ?? [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,22 +9,22 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Fido2" Version="4.0.0" />
|
<PackageReference Include="Fido2.AspNet" Version="4.0.1" />
|
||||||
<PackageReference Include="Grpc.AspNetCore" Version="2.76.0" />
|
<PackageReference Include="Grpc.AspNetCore" Version="2.76.0" />
|
||||||
<PackageReference Include="Grpc.AspNetCore.Web" Version="2.76.0" />
|
<PackageReference Include="Grpc.AspNetCore.Web" Version="2.76.0" />
|
||||||
<PackageReference Include="Grpc.Tools" Version="2.78.0">
|
<PackageReference Include="Grpc.Tools" Version="2.80.0">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0" />
|
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.3" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.5" />
|
||||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.16.0" />
|
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.17.0" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
||||||
<PackageReference Include="MimeTypesMap" Version="1.0.9" />
|
<PackageReference Include="MimeTypesMap" Version="1.0.9" />
|
||||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.0" />
|
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.2" />
|
||||||
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.9.0-beta.2" />
|
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.9.0-beta.2" />
|
||||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.0" />
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.2" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.0" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.1" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.0" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,16 @@ builder.Services.AddAuthentication(options =>
|
|||||||
|
|
||||||
|
|
||||||
builder.Services.AddAoba();
|
builder.Services.AddAoba();
|
||||||
|
builder.Services.AddFido2(opts =>
|
||||||
|
{
|
||||||
|
opts.ServerName = "Aoba";
|
||||||
|
opts.ServerDomain = "aoba.app";
|
||||||
|
#if DEBUG
|
||||||
|
opts.Origins = new HashSet<string> { "http://localhost:8081", "http://127.0.0.1:8080" };
|
||||||
|
#else
|
||||||
|
opts.Origins = new HashSet<string> { "https://aoba.app" };
|
||||||
|
#endif
|
||||||
|
});
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
builder.Services.AddHostedService<DebugService>();
|
builder.Services.AddHostedService<DebugService>();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import "google/protobuf/empty.proto";
|
|||||||
import "Proto/Types.proto";
|
import "Proto/Types.proto";
|
||||||
|
|
||||||
service AccountRpc {
|
service AccountRpc {
|
||||||
rpc RegisterPasskey(google.protobuf.Empty) returns (PasskeyRegistrationCreds);
|
rpc RegisterPasskey(google.protobuf.Empty) returns (PasskeyCredentialCreateOptions);
|
||||||
rpc CompletePasskeyRegistration(PasskeyPublicKey) returns (google.protobuf.Empty);
|
rpc CompletePasskeyRegistration(PasskeyRegistrationCredentials) returns (google.protobuf.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,9 +121,46 @@ message PasskeyPayload {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message PasskeyRegistrationCreds{
|
message PasskeyCredentialCreateOptions{
|
||||||
|
string challenge = 1;
|
||||||
|
PublicKeyCredentialUser user = 2;
|
||||||
|
PublicKeyCredentialRpEntity rp = 3;
|
||||||
|
repeated PubKeyCredParam pubKeyParams = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PubKeyCredParam{
|
||||||
|
string alg = 1;
|
||||||
|
string type = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PublicKeyCredentialRpEntity{
|
||||||
|
string id = 1;
|
||||||
|
string icon = 2;
|
||||||
|
string name = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PublicKeyCredentialUser{
|
||||||
|
string id = 1;
|
||||||
|
string name = 2;
|
||||||
|
string displayName = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PasskeyRegistrationCredentials{
|
||||||
|
string id = 1;
|
||||||
|
string rawId = 2;
|
||||||
|
string type = 3;
|
||||||
|
CredentialsClientResponse response = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CredentialsClientResponse{
|
||||||
|
string clientDataJSON = 1;
|
||||||
|
string attestationObject = 2;
|
||||||
|
string authenticatorData = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PublicKeyCredentialDescriptor{
|
||||||
|
string type = 1;
|
||||||
|
string id = 2;
|
||||||
|
repeated string transports = 3;
|
||||||
}
|
}
|
||||||
message PasskeyPublicKey{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,20 +1,50 @@
|
|||||||
using Aoba.RPC;
|
using Aoba.RPC;
|
||||||
using Aoba.RPC.Account;
|
using Aoba.RPC.Account;
|
||||||
|
|
||||||
|
using AobaCore.Services;
|
||||||
|
|
||||||
|
using AobaServer.Utils;
|
||||||
|
|
||||||
|
using Fido2NetLib;
|
||||||
|
|
||||||
using Google.Protobuf.WellKnownTypes;
|
using Google.Protobuf.WellKnownTypes;
|
||||||
|
|
||||||
using Grpc.Core;
|
using Grpc.Core;
|
||||||
|
|
||||||
|
using Isopoh.Cryptography.Argon2;
|
||||||
|
|
||||||
namespace AobaServer.Services;
|
namespace AobaServer.Services;
|
||||||
|
|
||||||
public class AccountRpcService : AccountRpc.AccountRpcBase
|
public class AccountRpcService(IFido2 fido2, AccountsService accounts) : AccountRpc.AccountRpcBase
|
||||||
{
|
{
|
||||||
public override Task<PasskeyRegistrationCreds> RegisterPasskey(Empty request, ServerCallContext context)
|
public override async Task<PasskeyCredentialCreateOptions> RegisterPasskey(Empty request, ServerCallContext context)
|
||||||
{
|
{
|
||||||
return base.RegisterPasskey(request, context);
|
var curUser = await accounts.GetUserAsync(context.GetUserId(), context.CancellationToken);
|
||||||
|
if (curUser == null)
|
||||||
|
throw new Exception($"Logged in user does not exist somehow. Id: {context.GetUserId()}");
|
||||||
|
var user = new Fido2User
|
||||||
|
{
|
||||||
|
DisplayName = curUser.Username,
|
||||||
|
Id = curUser.Id.ToByteArray(),
|
||||||
|
Name = curUser.Username
|
||||||
|
};
|
||||||
|
|
||||||
|
var credOptions = fido2.RequestNewCredential(new RequestNewCredentialParams
|
||||||
|
{
|
||||||
|
User = user,
|
||||||
|
ExcludeCredentials = curUser.CredentialDescriptors,
|
||||||
|
AuthenticatorSelection = new AuthenticatorSelection
|
||||||
|
{
|
||||||
|
ResidentKey = Fido2NetLib.Objects.ResidentKeyRequirement.Required,
|
||||||
|
UserVerification = Fido2NetLib.Objects.UserVerificationRequirement.Preferred
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return credOptions.ToRPC();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<Empty> CompletePasskeyRegistration(PasskeyPublicKey request, ServerCallContext context)
|
public override Task<Empty> CompletePasskeyRegistration(PasskeyRegistrationCredentials request, ServerCallContext context)
|
||||||
{
|
{
|
||||||
return base.CompletePasskeyRegistration(request, context);
|
return base.CompletePasskeyRegistration(request, context);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using Aoba.RPC;
|
||||||
|
|
||||||
|
using Isopoh.Cryptography.Argon2;
|
||||||
|
|
||||||
|
namespace AobaServer.Utils;
|
||||||
|
|
||||||
|
public static class PasskeyExtensions
|
||||||
|
{
|
||||||
|
public static PublicKeyCredentialRpEntity ToRPC(this Fido2NetLib.PublicKeyCredentialRpEntity value)
|
||||||
|
{
|
||||||
|
return new PublicKeyCredentialRpEntity
|
||||||
|
{
|
||||||
|
Id = value.Id,
|
||||||
|
Icon = value.Icon,
|
||||||
|
Name = value.Name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PublicKeyCredentialUser ToRPC(this Fido2NetLib.Fido2User value)
|
||||||
|
{
|
||||||
|
return new PublicKeyCredentialUser
|
||||||
|
{
|
||||||
|
Id = value.Id.ToB64String(),
|
||||||
|
DisplayName = value.DisplayName,
|
||||||
|
Name = value.Name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PubKeyCredParam ToRPC(this Fido2NetLib.PubKeyCredParam value)
|
||||||
|
{
|
||||||
|
return new PubKeyCredParam
|
||||||
|
{
|
||||||
|
Alg = value.Alg.ToString(),
|
||||||
|
Type = value.Type.ToString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PubKeyCredParam> ToRPC(this IEnumerable<Fido2NetLib.PubKeyCredParam> value)
|
||||||
|
{
|
||||||
|
return value.Select(x => x.ToRPC());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PasskeyCredentialCreateOptions ToRPC(this Fido2NetLib.CredentialCreateOptions value)
|
||||||
|
{
|
||||||
|
var opts = new PasskeyCredentialCreateOptions
|
||||||
|
{
|
||||||
|
Challenge = value.Challenge.ToB64String(),
|
||||||
|
Rp = value.Rp.ToRPC(),
|
||||||
|
User = value.User.ToRPC()
|
||||||
|
};
|
||||||
|
//todo: excluded credentials
|
||||||
|
opts.PubKeyParams.AddRange(value.PubKeyCredParams.ToRPC());
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user