change everything -- use thaw ui

This commit is contained in:
Adam 2024-09-09 19:46:56 -04:00
parent 88a308ad6c
commit 0729ffc077
19 changed files with 824 additions and 499 deletions

334
Cargo.lock generated
View file

@ -4,19 +4,13 @@ version = 3
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.22.0" version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375"
dependencies = [ dependencies = [
"gimli", "gimli",
] ]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]] [[package]]
name = "adler2" name = "adler2"
version = "2.0.0" version = "2.0.0"
@ -222,17 +216,17 @@ dependencies = [
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.73" version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [ dependencies = [
"addr2line", "addr2line",
"cc",
"cfg-if", "cfg-if",
"libc", "libc",
"miniz_oxide 0.7.4", "miniz_oxide",
"object", "object",
"rustc-demangle", "rustc-demangle",
"windows-targets",
] ]
[[package]] [[package]]
@ -351,6 +345,7 @@ dependencies = [
"codee", "codee",
"console_error_panic_hook", "console_error_panic_hook",
"console_log", "console_log",
"icondata",
"leptos", "leptos",
"leptos-use", "leptos-use",
"leptos_meta", "leptos_meta",
@ -679,7 +674,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide 0.8.0", "miniz_oxide",
] ]
[[package]] [[package]]
@ -811,9 +806,9 @@ dependencies = [
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.29.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
[[package]] [[package]]
name = "gloo-net" name = "gloo-net"
@ -942,9 +937,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]] [[package]]
name = "hydration_context" name = "hydration_context"
version = "0.2.0-beta4" version = "0.2.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fd272e5549af207e00abfcbb622a7991f0a15ee12b86a7c3cfef41758a83f43" checksum = "b807c29c4af72bfcc71a4427625749ad7a0c22b936f8a1a82f464140b633afe6"
dependencies = [ dependencies = [
"futures", "futures",
"once_cell", "once_cell",
@ -975,9 +970,9 @@ dependencies = [
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.7" version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-util", "futures-util",
@ -1011,6 +1006,33 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "icondata"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18db9eec46b6c870bf84281dd8065fb207b23a9c1c0cb367c49a919a61a38dec"
dependencies = [
"icondata_ai",
"icondata_bi",
"icondata_bs",
"icondata_cg",
"icondata_ch",
"icondata_core",
"icondata_fa",
"icondata_fi",
"icondata_hi",
"icondata_im",
"icondata_io",
"icondata_lu",
"icondata_oc",
"icondata_ri",
"icondata_si",
"icondata_tb",
"icondata_ti",
"icondata_vs",
"icondata_wi",
]
[[package]] [[package]]
name = "icondata_ai" name = "icondata_ai"
version = "0.0.10" version = "0.0.10"
@ -1020,12 +1042,165 @@ dependencies = [
"icondata_core", "icondata_core",
] ]
[[package]]
name = "icondata_bi"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6ce125f0d203e66444b02982af9b15631f2385573ad7992af79d4d4babc638d"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_bs"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67940e592b0b8df8d7adc055c8542d135ce1d7d6ad01d8fb8de9405ebfc21c2e"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_cg"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0eba691ca17a43ffc8ebbcf200cd3ea54ad75837f210a6a6ace87a491be8314"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_ch"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2870b3c4ebf013b7e27af71d4c55f10b97ea448831e9a156cb53fec0f262dc20"
dependencies = [
"icondata_core",
]
[[package]] [[package]]
name = "icondata_core" name = "icondata_core"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c97be924215abd5e630d84e95a47c710138a6559b4c55039f4f33aa897fa859" checksum = "6c97be924215abd5e630d84e95a47c710138a6559b4c55039f4f33aa897fa859"
[[package]]
name = "icondata_fa"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c7fee576096efe5567a7216a6fb8154db8eae9ae108e5a4706805204208c2af"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_fi"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1a4e81557c205a12ac051046595bb616f388537468987f7ee8960f897cdc538"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_hi"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3435d50de04c61799613995e753e613dc4f2771aa08eb94a7318289a5ea9d784"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_im"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce4bd1d64bb67bb080f605e3e600271894b67c4aaa18965179586ef5990a2297"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_io"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35b9d681c936a6e087940beb4766159cddc080d7f1fd5ef0ef3ab9f50a11f3f6"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_lu"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d552c45cc3ab1d1bf88cc0201004eb92418141e5454e9e0e46c4b4a4faf66248"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_oc"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8be19499912a05d5db89ccb88dbe3c459ca4100bda3dbcbddff69f2dcf71d305"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_ri"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "114a85cc95d1bfaee8dc5bf8a07dd043fc9e75499dc2ff4ac5e066193c594930"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_si"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc30cb2dbc2ac53f23dddbcb0ad73720970b24c0ed13935df8082b74fb627860"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_tb"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f2b8d8e2047546285805795e6d3cb6e820a52bb008e15942e11353c7ba659f2"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_ti"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f85074d4bf10960d0f2b01ce3d9cfa2b2434a170d0738336411bb61e83227e4"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_vs"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a82bb4a8b1523200fc7c3b588bb80858db16708067093110ee8614db63b8913"
dependencies = [
"icondata_core",
]
[[package]]
name = "icondata_wi"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d2c65b534aa9d7ccb107d892200e8fef2d1849acad160af067e9e20ced3619b"
dependencies = [
"icondata_core",
]
[[package]] [[package]]
name = "ident_case" name = "ident_case"
version = "1.0.1" version = "1.0.1"
@ -1099,9 +1274,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "leptos" name = "leptos"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4eb1451927cce0a17cc3af6fdad18911eae7c827bb90a5117fa463b5b109ce4" checksum = "dce271592769bc3aaece4b23228176fe2862b24666a6ad1d49639af9e3081f93"
dependencies = [ dependencies = [
"any_spawner", "any_spawner",
"cfg-if", "cfg-if",
@ -1134,9 +1309,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos-use" name = "leptos-use"
version = "0.14.0-beta1" version = "0.14.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf3e115ec6c90ccd031c1f94918372af602f105e0b3b252363f0ef887d15a1aa" checksum = "424197a4dfb2cb8814d6be2baae4bcae9d56ce196b3febb7c020ebc282fe334c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"codee", "codee",
@ -1158,9 +1333,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_config" name = "leptos_config"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db9b3c211cc072b742a728a71e86969034e7ab75ae68205d604df047b9ffb87e" checksum = "c4cbdc8ee8cb4d4f808f0281a9c3164abeb8e2a9e647bed8761f4caf13182933"
dependencies = [ dependencies = [
"config", "config",
"regex", "regex",
@ -1171,9 +1346,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_dom" name = "leptos_dom"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d356526ed1c9be0804b297b0bf5d768490840d4669bd52e63f6b68d5693f7e7" checksum = "db28172a39d7b8f97c69ad8dbc3a2c05a244ade74f1da9bc0bd557d25914d8b1"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"or_poisoned", "or_poisoned",
@ -1186,9 +1361,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_hot_reload" name = "leptos_hot_reload"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121e56d24140488617d3554674708f0c00deaa287ff7ab01609fd590f32fafc8" checksum = "39d2b962cac155477b5ee82587c50235b2e1b88b657930b9cb5b9250352a3347"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"camino", "camino",
@ -1204,9 +1379,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_macro" name = "leptos_macro"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5dca48e1894486f762bef0e0de24e39f1bf3a1ae84ab49915a9864856b57961" checksum = "e98a32e24e3c4998d162ea71c9299e1fe0d38005b714fe30225ae613d9f0bf05"
dependencies = [ dependencies = [
"attribute-derive", "attribute-derive",
"cfg-if", "cfg-if",
@ -1215,7 +1390,7 @@ dependencies = [
"itertools", "itertools",
"leptos_hot_reload", "leptos_hot_reload",
"prettyplease", "prettyplease",
"proc-macro-error", "proc-macro-error2",
"proc-macro2", "proc-macro2",
"quote", "quote",
"rstml", "rstml",
@ -1226,9 +1401,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_meta" name = "leptos_meta"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68327b651ff5ea1341faadbaefad9a5fa22160fe70651618aa2883422eee8f36" checksum = "773788bc79b195fd4af745d0eb59e08435bcfb5eb068ebdda018fbe1302685c7"
dependencies = [ dependencies = [
"futures", "futures",
"indexmap", "indexmap",
@ -1242,9 +1417,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_router" name = "leptos_router"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "810ba3c70df80581c534792fa8294a1ddef2896fedc0bd60b73bce141f7068bf" checksum = "44c79346efd7b0fe1884a9a6dda3d7f92dae4bef7be9ef65c6dd80d2ba5c4fb8"
dependencies = [ dependencies = [
"any_spawner", "any_spawner",
"either_of", "either_of",
@ -1258,6 +1433,7 @@ dependencies = [
"paste", "paste",
"reactive_graph", "reactive_graph",
"send_wrapper", "send_wrapper",
"serde",
"tachys", "tachys",
"thiserror", "thiserror",
"url", "url",
@ -1267,9 +1443,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_router_macro" name = "leptos_router_macro"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "644f00cd2ab91b7086a5b8b339cffab247ed1a34e027758405c6881b63ed26f2" checksum = "9cc536868a8d444ee14e763addfde2e44f94786bb71122bb0f0f5356748ee125"
dependencies = [ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
@ -1278,9 +1454,9 @@ dependencies = [
[[package]] [[package]]
name = "leptos_server" name = "leptos_server"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bae878288fea9931571a1a9cc471161d3c595e990aa41f4f1a9aaa0cf8d0ccdd" checksum = "b1250915d58d808b763aa17f3d873e0dcd1e8c72ba1f2f557c2889ff03494f23"
dependencies = [ dependencies = [
"any_spawner", "any_spawner",
"base64 0.22.1", "base64 0.22.1",
@ -1288,6 +1464,7 @@ dependencies = [
"futures", "futures",
"hydration_context", "hydration_context",
"reactive_graph", "reactive_graph",
"send_wrapper",
"serde", "serde",
"serde_json", "serde_json",
"server_fn", "server_fn",
@ -1408,15 +1585,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
dependencies = [
"adler",
]
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.0" version = "0.8.0"
@ -1440,9 +1608,9 @@ dependencies = [
[[package]] [[package]]
name = "next_tuple" name = "next_tuple"
version = "0.1.0-beta4" version = "0.1.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66dadf287063ab08b1247d1be56e9656b272b10423896fb60d49881f69b2b266" checksum = "bf84e075aa6ad90a5868f864c36ba983b2ffc52d1f584899398ae248fd77b414"
[[package]] [[package]]
name = "nom" name = "nom"
@ -1715,6 +1883,27 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "proc-macro-error-attr2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "proc-macro-error2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
]
[[package]] [[package]]
name = "proc-macro-utils" name = "proc-macro-utils"
version = "0.8.0" version = "0.8.0"
@ -1822,9 +2011,9 @@ dependencies = [
[[package]] [[package]]
name = "reactive_graph" name = "reactive_graph"
version = "0.1.0-beta4" version = "0.1.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "277ddf442e2675c536ff4088bae41c937ae4a3a821b53ecaa386c5f911252e2f" checksum = "03a4ad833d7f44ca640ad93e7169b263ca9ecdc1a9599cdb6ca5c02e5b24656a"
dependencies = [ dependencies = [
"any_spawner", "any_spawner",
"async-lock", "async-lock",
@ -2049,7 +2238,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"tokio", "tokio",
"tower 0.5.0", "tower 0.5.1",
"tower-http", "tower-http",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
@ -2058,9 +2247,9 @@ dependencies = [
[[package]] [[package]]
name = "server_fn" name = "server_fn"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b802f1cfb1965eb17046f23401597766fc149ffd5a904ab43b55cad41899a6f" checksum = "0c6ca573753dbd6777647be6d98bfed22d0d71e205eb1126bf6bc85c42affc2f"
dependencies = [ dependencies = [
"bytes", "bytes",
"const_format", "const_format",
@ -2088,9 +2277,9 @@ dependencies = [
[[package]] [[package]]
name = "server_fn_macro" name = "server_fn_macro"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3b2d6ea0d021a2a21ce64142d589f84e4f0b08c44318f7088d9c6e5ad24b08" checksum = "63c8d47c8c8524526633b79c48e9ded61ed00670e45ebb900b22e23815888b70"
dependencies = [ dependencies = [
"const_format", "const_format",
"convert_case", "convert_case",
@ -2102,9 +2291,9 @@ dependencies = [
[[package]] [[package]]
name = "server_fn_macro_default" name = "server_fn_macro_default"
version = "0.7.0-beta4" version = "0.7.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c3cdf66b25e36aab3a9aca2c675c60645ebbb2ab78294f88957d2870cf72020" checksum = "7b2439cb2af4644cb59653db8d6e68e8d75c1cd9e82dea2d98f29f32ba5f4a0b"
dependencies = [ dependencies = [
"server_fn_macro", "server_fn_macro",
"syn", "syn",
@ -2228,9 +2417,9 @@ checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
[[package]] [[package]]
name = "tachys" name = "tachys"
version = "0.1.0-beta4" version = "0.1.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ae9c2a49cafbeacdf5991b2ab48236d7711159ede8510c2efb6be8a28665ee7" checksum = "2fd5906862cc50f3a32da67184a0259c5ee991d67d9c38e8cd87e63f8d9df142"
dependencies = [ dependencies = [
"any_spawner", "any_spawner",
"const_str_slice_concat", "const_str_slice_concat",
@ -2248,7 +2437,6 @@ dependencies = [
"or_poisoned", "or_poisoned",
"parking_lot", "parking_lot",
"paste", "paste",
"pin-project-lite",
"reactive_graph", "reactive_graph",
"rustc-hash", "rustc-hash",
"send_wrapper", "send_wrapper",
@ -2261,8 +2449,7 @@ dependencies = [
[[package]] [[package]]
name = "thaw" name = "thaw"
version = "0.4.0-beta2" version = "0.4.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/adoyle0/thaw.git#aa818b28239fedd76d4e7ee3f7b541a9fd67c6bc"
checksum = "a10abe67825fbd871289ec6fd5fea9cf92691d1da32707c00e7af70577306d62"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"chrono", "chrono",
@ -2284,8 +2471,7 @@ dependencies = [
[[package]] [[package]]
name = "thaw_components" name = "thaw_components"
version = "0.2.0-beta2" version = "0.2.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/adoyle0/thaw.git#aa818b28239fedd76d4e7ee3f7b541a9fd67c6bc"
checksum = "4ee0d5671ca0280910de0f69288aa20a98249c5a2a9fddccb2525d750a124f94"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"leptos", "leptos",
@ -2298,8 +2484,7 @@ dependencies = [
[[package]] [[package]]
name = "thaw_macro" name = "thaw_macro"
version = "0.1.0-beta2" version = "0.1.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/adoyle0/thaw.git#aa818b28239fedd76d4e7ee3f7b541a9fd67c6bc"
checksum = "4adff1cd2cd4da053f7d912e34e2e696b28d34561ff5929c2077c0ed7ee2834c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2309,8 +2494,7 @@ dependencies = [
[[package]] [[package]]
name = "thaw_utils" name = "thaw_utils"
version = "0.1.0-beta2" version = "0.1.0-beta2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/adoyle0/thaw.git#aa818b28239fedd76d4e7ee3f7b541a9fd67c6bc"
checksum = "0a9554f2a9d236925dd1cae57d1c3e1f6390f20ff31aa9999d1b41bcc1f8d551"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"chrono", "chrono",
@ -2352,9 +2536,9 @@ dependencies = [
[[package]] [[package]]
name = "throw_error" name = "throw_error"
version = "0.2.0-beta4" version = "0.2.0-beta5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3c1e41506da98dbdac683e12a2c87813d218f0540dab31c94343ef29a4c062" checksum = "bf4f5aa80794461408e66eacde42bdc1c0fa6a626c75601c1e909c6267750915"
dependencies = [ dependencies = [
"pin-project-lite", "pin-project-lite",
] ]
@ -2520,9 +2704,9 @@ dependencies = [
[[package]] [[package]]
name = "tower" name = "tower"
version = "0.5.0" version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36b837f86b25d7c0d7988f00a54e74739be6477f2aac6201b8f429a7569991b7" checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-util", "futures-util",

View file

@ -15,11 +15,20 @@ console_log = "1"
log = "0.4" log = "0.4"
leptos-use = "0.14.0-beta" leptos-use = "0.14.0-beta"
# leptos-use = { path = "../../leptos-use" }
# leptos-use = { git = "https://github.com/adoyle0/leptos-use.git", branch = "leptos-0.7" }
codee = "0.2" codee = "0.2"
lib = { workspace = true } lib = { workspace = true }
serde_json = "1.0" serde_json = "1.0"
thaw = { version = "0.4.0-beta2", features = ["csr", "nightly"] }
# thaw = { version = "0.4.0-beta", features = ["csr", "nightly"] }
# thaw = { path = "../../thaw/thaw", features = ["csr", "nightly"] }
thaw = { git = "https://github.com/adoyle0/thaw.git", features = [
"csr",
"nightly",
] }
icondata = "0.4"
[dev-dependencies] [dev-dependencies]
wasm-bindgen = "0.2" wasm-bindgen = "0.2"

View file

@ -2,6 +2,7 @@
<html> <html>
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link data-trunk rel="rust" data-target-path="client" data-wasm-opt="z" data-weak-refs /> <link data-trunk rel="rust" data-target-path="client" data-wasm-opt="z" data-weak-refs />
<link data-trunk rel="icon" href="public/favicon.ico" /> <link data-trunk rel="icon" href="public/favicon.ico" />
<link data-trunk rel="tailwind-css" href="public/styles.css" /> <link data-trunk rel="tailwind-css" href="public/styles.css" />

View file

@ -4,32 +4,11 @@
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap");
.inter-med {
font-family: "Inter", sans-serif;
font-optical-sizing: auto;
font-weight: 400;
font-style: normal;
}
html, html,
body { body {
@apply text-neutral-200 bg-neutral-900;
font-family: "Inter", sans-serif; font-family: "Inter", sans-serif;
font-optical-sizing: auto; font-optical-sizing: auto;
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
font-stretch: condensed; font-stretch: condensed;
} }
button {
@apply bg-neutral-600
border-b-4
border-neutral-800
font-bold
hover:bg-neutral-700
hover:border-neutral-500
px-4
py-2
rounded
text-white;
}

View file

@ -1,72 +1,118 @@
use crate::components::websocket::WebSocketContext; use crate::components::websocket::WebSocketContext;
use leptos::{html::Input, prelude::*}; use leptos::{ev, prelude::*};
use leptos_use::core::ConnectionReadyState; use leptos_use::core::ConnectionReadyState;
use lib::*; use lib::*;
use serde_json::to_string; use serde_json::to_string;
use thaw::*;
#[component] #[component]
pub fn Auth() -> impl IntoView { pub fn Auth() -> impl IntoView {
let websocket = expect_context::<WebSocketContext>(); let websocket = expect_context::<WebSocketContext>();
let (username, set_username) = signal("".to_string()); let username = RwSignal::new("".to_string());
let user_context = expect_context::<ReadSignal<Option<UserUpdate>>>(); let user_context = expect_context::<ReadSignal<Option<UserUpdate>>>();
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open; let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
let new_username = RwSignal::new(String::new());
let show_auth = RwSignal::new(false);
Effect::new(move |_| { Effect::new(move |_| {
user_context.with(|new_user| { user_context.with(|new_user| {
if let Some(user) = new_user { if let Some(user) = new_user {
set_username(user.username.to_string()); username.set(user.username.to_string());
} }
}) });
}); });
let username_input_ref = NodeRef::<Input>::new();
let send_login = move |_| { let send_login = move |_| {
if let Some(input) = username_input_ref.get() { websocket.send(
if input.value() != String::from("") { &to_string(&UserLogInRequest {
websocket.send( username: new_username(),
&to_string(&UserLogInRequest { })
username: input.value(), .unwrap(),
}) );
.unwrap(), new_username.set(String::new());
);
set_username.set("".to_string());
input.set_value("");
}
}
}; };
// Clear user name on disconnect // Clear user name on disconnect
Effect::new(move |_| { Effect::new(move |_| {
if !connected() { if !connected() {
set_username(String::from("")); username.set(String::from(""));
} }
}); });
view! { view! {
<div class="my-2"> <div class="flex flex-wrap justify-between">
<h2 class="text-2xl">Sign in:</h2> <p class="my-2">"Welcome " {move || username()}"!"</p>
<Show when=move || { connected() } fallback=|| view! { <p>"Disconnected."</p> }> <Button
<p> appearance=ButtonAppearance::Transparent
"You were already given a random name but if you'd like to change it this is the place. Identities are saved once created so if you leave or get disconnected just enter your old name here to \"log back in\". Please don't steal each other's identities (yes, you can)." size=ButtonSize::Small
</p> on_click=move |_| { show_auth.set(!show_auth()) }
<br /> >
<p>Username:</p> <Avatar name=username />
<form onsubmit="return false" on:submit=send_login.clone()> </Button>
<input </div>
class="w-96 font-mono rounded-sm bg-neutral-900 text-neutral-200" <div class="overflow-hidden">
placeholder=move || username.get() <InlineDrawer open=show_auth position=DrawerPosition::Top size=DrawerSize::Small>
node_ref=username_input_ref <DrawerBody>
disabled=move || !connected() <Show when=move || { connected() } fallback=|| view! { <p>"Disconnected."</p> }>
/> <Popover
<br /> trigger_type=PopoverTriggerType::Click
<input position=PopoverPosition::BottomStart
class="py-2 px-4 pl-4 font-bold text-white rounded border-b-4 bg-neutral-600 border-neutral-800 hover:bg-neutral-700 hover:border-neutral-500" >
type="submit" <PopoverTrigger slot>
value="Send" <h2 class="text-2xl">
disabled=move || !connected() "Sign In"
/> <Button
</form> icon=icondata::TbHelp
</Show> appearance=ButtonAppearance::Transparent
size=ButtonSize::Small
/>
</h2>
</PopoverTrigger>
<p class="indent-1 text-pretty">
"You were already given a random name but if you'd like to change it this is the place."
</p>
<p class="my-2 indent-1 text-pretty">
"Identities are saved once created so if you leave or get disconnected just enter your old name here to \"log back in\"."
</p>
<p class="indent-1 text-pretty">
"Please don't steal each other's identities (yes, you can)."
</p>
</Popover>
<br />
<form onsubmit="return false" on:submit=send_login.clone() autocomplete="off">
<FieldContextProvider>
<Field label="Username" name="username">
<Input
placeholder=username
value=new_username
disabled=!connected()
class="w-80"
rules=vec![InputRule::required(true.into())]
>
<InputPrefix slot>
<Icon icon=icondata::AiUserOutlined />
</InputPrefix>
</Input>
</Field>
<Button
button_type=ButtonType::Submit
on_click={
let field_context = FieldContextInjection::expect_context();
move |e: ev::MouseEvent| {
if !field_context.validate() {
e.prevent_default();
}
}
}
>
"Submit"
</Button>
</FieldContextProvider>
</form>
</Show>
</DrawerBody>
</InlineDrawer>
</div> </div>
} }
} }

View file

@ -1,8 +1,11 @@
use crate::components::browser::create_game::*;
use crate::components::websocket::WebSocketContext; use crate::components::websocket::WebSocketContext;
use leptos::prelude::*; use leptos::prelude::*;
use leptos_use::core::ConnectionReadyState; use leptos_use::core::ConnectionReadyState;
use lib::*; use lib::*;
use serde_json::to_string; use serde_json::to_string;
use thaw::*;
pub mod create_game;
#[component] #[component]
pub fn Browser() -> impl IntoView { pub fn Browser() -> impl IntoView {
@ -37,67 +40,137 @@ pub fn Browser() -> impl IntoView {
); );
}); });
let show_create_game = RwSignal::new(false);
provide_context(show_create_game);
view! { view! {
<div class="my-2"> <div class="my-2">
<h2 class="text-2xl">Game Browser</h2> <div class="flex flex-wrap justify-between">
<Popover
trigger_type=PopoverTriggerType::Click
position=PopoverPosition::BottomStart
>
<PopoverTrigger slot>
<h2 class="text-2xl">
"Game Browser"
<Button
icon=icondata::TbHelp
appearance=ButtonAppearance::Transparent
size=ButtonSize::Small
/>
</h2>
</PopoverTrigger>
<p>"Yes, the delete button works. Please don't abuse it."</p>
</Popover>
<Button
icon=icondata::AiPlusOutlined
appearance=ButtonAppearance::Primary
size=ButtonSize::Small
on_click=move |_| show_create_game.set(!show_create_game())
>
"Create Game"
</Button>
</div>
<Show when=move || { connected() } fallback=|| view! { <p>"Disconnected."</p> }> <Show when=move || { connected() } fallback=|| view! { <p>"Disconnected."</p> }>
<Show <Show
when=move || { game_browser_context().len() > 0 } when=move || { game_browser_context().len() > 0 }
fallback=|| { fallback=|| {
view! { "No games to show right now.. Maybe you should create one!" } view! { <p>"No games to show right now.. Maybe you should create one!"</p> }
} }
> >
<p>"Yes, the delete button works. Please don't abuse it."</p>
<div> <div>
<table class="min-w-full border border-collapse table-auto"> <Table>
<thead> <TableHeader>
<tr> <TableRow>
<th class="border-b">Name</th> <TableHeaderCell class="justify-center">
<th class="border-b">Host</th> <p>Name</p>
<th class="border-b">Players</th> </TableHeaderCell>
<th class="border-b">Card Packs</th> <TableHeaderCell class="justify-center">
<th class="border-b"></th> <p>Host</p>
</tr> </TableHeaderCell>
</thead> <TableHeaderCell class="justify-center">
<p>Players</p>
</TableHeaderCell>
<TableHeaderCell class="justify-center">
<p>Card Packs</p>
</TableHeaderCell>
<TableHeaderCell></TableHeaderCell>
</TableRow>
</TableHeader>
// This rebuilds the entire browser each time it runs but using <For /> won't update the children if the id doesn't change // This rebuilds the entire browser each time it runs but using <For /> won't update the children if the id doesn't change
{game_browser_context() {move || {
.iter() game_browser_context()
.cloned() .iter()
.map(|game| { .cloned()
view! { .map(|game| {
<tr> view! {
<td class="text-center border-b">{game.name}</td> <TableBody>
<td class="text-center border-b">{game.host}</td> <TableRow>
<td class="text-center border-b">{game.players}</td> <TableCell>
<td class="text-center border-b">{game.packs.len()}</td> <TableCellLayout class="justify-center">
<td class="text-center border-b"> <p>{game.name}</p>
<button </TableCellLayout>
type="button" </TableCell>
value=game.uuid.clone() <TableCell>
on:click=move |e| { <TableCellLayout class="justify-center">
set_join_id(event_target_value(&e)); {game.host}
} </TableCellLayout>
> </TableCell>
Join <TableCell>
</button> <TableCellLayout class="justify-center">
<button {game.players}
type="button" </TableCellLayout>
value=game.uuid.clone() </TableCell>
on:click=move |e| { <TableCell>
set_delete_id(event_target_value(&e)); <TableCellLayout class="justify-center">
} {game.packs.len()}
> </TableCellLayout>
Delete </TableCell>
</button> <TableCell>
</td> <TableCellLayout class="flex flex-wrap justify-center">
</tr> <Button
} appearance=ButtonAppearance::Primary
}) size=ButtonSize::Small
.collect_view()} on_click={
</table> let game_id = game.uuid.clone();
move |_| {
set_join_id(game_id.clone());
}
}
>
"Join"
</Button>
<Button
appearance=ButtonAppearance::Secondary
size=ButtonSize::Small
icon=icondata::TiDeleteOutline
on_click=move |_| {
set_delete_id(game.uuid.clone());
}
>
"Delete"
</Button>
</TableCellLayout>
</TableCell>
</TableRow>
</TableBody>
}
})
.collect_view()
}}
</Table>
</div> </div>
</Show> </Show>
<div class="overflow-hidden">
<InlineDrawer open=show_create_game position=DrawerPosition::Top>
<DrawerBody>
<CreateGame />
</DrawerBody>
</InlineDrawer>
</div>
</Show> </Show>
</div> </div>
} }

View file

@ -0,0 +1,163 @@
use crate::components::websocket::WebSocketContext;
use leptos::{ev, prelude::*};
use leptos_use::core::ConnectionReadyState;
use lib::*;
use serde_json::to_string;
use std::collections::HashSet;
use thaw::*;
#[component]
pub fn CreateGame() -> impl IntoView {
// Websocket stuff
let websocket = expect_context::<WebSocketContext>();
let (websocket_send, set_websocket_send) = signal("".to_string());
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
let tx = websocket.clone();
Effect::new(move |_| {
if websocket_send() != "".to_string() {
tx.send(&websocket_send());
}
});
// New game stuff
let card_packs = expect_context::<ReadSignal<CardPacksMeta>>();
let show_packs = RwSignal::new(false);
let selected_packs = RwSignal::<HashSet<String>>::new(HashSet::new());
Effect::new(move |_| {
selected_packs.update(|packs| {
for pack in card_packs().official_meta {
packs.insert(pack.pack);
}
for pack in card_packs().unofficial_meta {
packs.insert(pack.pack);
}
})
});
let input_game_name = RwSignal::new(String::new());
let toggle_show_packs = move |_| show_packs.set(!show_packs());
let drawer_context = expect_context::<RwSignal<bool>>();
let request_new_game = move |_| {
set_websocket_send(
to_string(&NewGameRequest {
name: input_game_name(),
packs: selected_packs(),
})
.unwrap(),
);
input_game_name.set(String::new());
drawer_context.set(false);
};
view! {
<div class="my-2">
<h2 class="text-2xl">"Create Game"</h2>
<Show when=move || connected() fallback=|| view! { <p>"Disconnected."</p> }>
<div class="flex">
<form onsubmit="return false" on:submit=request_new_game autocomplete="off">
<FieldContextProvider>
<Field label="Game Name" name="name">
<Input
value=input_game_name
disabled=!connected()
rules=vec![InputRule::required(true.into())]
/>
</Field>
<Popover
trigger_type=PopoverTriggerType::Click
position=PopoverPosition::BottomStart
>
<PopoverTrigger slot>
<h2 class="text-2xl">
"Packs"
<Button
icon=icondata::TbHelp
button_type=ButtonType::Button
appearance=ButtonAppearance::Transparent
size=ButtonSize::Small
/>
</h2>
</PopoverTrigger>
<p>"All 205 card packs are enabled by default"</p>
</Popover>
<div class="p-2">
<Button button_type=ButtonType::Button on_click=toggle_show_packs>
"Customize"
</Button>
</div>
<Show when=move || show_packs()>
<span class="flex">
<div>
<h2 class="text-xl">Official</h2>
<CheckboxGroup value=selected_packs>
{move || {
card_packs()
.official_meta
.into_iter()
.map(|n| {
view! {
<Checkbox
label=n.name
checked=selected_packs().contains(&n.pack)
value=n.pack
/>
<br />
}
})
.collect_view()
}}
</CheckboxGroup>
</div>
<div>
<h2 class="text-xl">Unofficial</h2>
<CheckboxGroup value=selected_packs>
{move || {
card_packs()
.unofficial_meta
.into_iter()
.map(|n| {
view! {
<Checkbox
label=n.name
checked=selected_packs().contains(&n.pack)
value=n.pack
/>
<br />
}
})
.collect_view()
}}
</CheckboxGroup>
</div>
</span>
</Show>
<Button
button_type=ButtonType::Submit
on_click={
let field_context = FieldContextInjection::expect_context();
move |e: ev::MouseEvent| {
if !field_context.validate() {
e.prevent_default();
}
}
}
>
"Create Game"
</Button>
</FieldContextProvider>
</form>
</div>
</Show>
</div>
}
}

View file

@ -1,11 +1,13 @@
use crate::components::websocket::WebSocketContext; use crate::components::websocket::WebSocketContext;
use leptos::{ use leptos::{
ev,
html::{Input, Textarea}, html::{Input, Textarea},
prelude::*, prelude::*,
}; };
use leptos_use::core::ConnectionReadyState; use leptos_use::core::ConnectionReadyState;
use lib::*; use lib::*;
use serde_json::to_string; use serde_json::to_string;
use thaw::*;
#[component] #[component]
pub fn Chat() -> impl IntoView { pub fn Chat() -> impl IntoView {
@ -15,33 +17,29 @@ pub fn Chat() -> impl IntoView {
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open; let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
// Chat stuff // Chat stuff
let (chat_history, set_chat_history) = signal::<Vec<String>>(vec![]); let chat_history = RwSignal::<Vec<String>>::new(vec![]);
let (users, set_users) = signal::<Vec<String>>(vec![]); let users = RwSignal::<Vec<String>>::new(vec![]);
let (chat_name, set_chat_name) = signal::<String>("".to_string()); let chat_name = RwSignal::<String>::new("".to_string());
let chat_history_ref = NodeRef::<Textarea>::new(); let chat_input = RwSignal::new(String::new());
let chat_input_ref = NodeRef::<Input>::new(); let chat_input_ref = NodeRef::<Input>::new();
let chat_history_ref = NodeRef::<Textarea>::new();
fn update_chat_history(&history: &WriteSignal<Vec<String>>, message: String) {
let _ = &history.update(|history: &mut Vec<_>| history.push(message));
}
// Connection status updates in chat window // Connection status updates in chat window
Effect::new(move |_| { Effect::new(move |_| {
websocket.ready_state.with(move |state| match *state { websocket.ready_state.with(move |state| match *state {
ConnectionReadyState::Connecting => { ConnectionReadyState::Connecting => {
update_chat_history( chat_history
&set_chat_history, .update(|history| history.push("Connecting to game server...\n".to_string()));
"Connecting to game server...\n".to_string(),
);
} }
ConnectionReadyState::Open => { ConnectionReadyState::Open => {
update_chat_history(&set_chat_history, "Connected!\n".to_string()); chat_history.update(|history| history.push("Connected!\n".to_string()));
} }
ConnectionReadyState::Closing => { ConnectionReadyState::Closing => {
update_chat_history(&set_chat_history, "Disconnecting...\n".to_string()); chat_history.update(|history| history.push("Disconnecting...\n".to_string()));
} }
ConnectionReadyState::Closed => { ConnectionReadyState::Closed => {
update_chat_history(&set_chat_history, "Disconnected.\n".to_string()); chat_history.update(|history| history.push("Disconnected.\n".to_string()));
users.update(|users| users.clear());
} }
}) })
}); });
@ -50,7 +48,7 @@ pub fn Chat() -> impl IntoView {
Effect::new(move |_| { Effect::new(move |_| {
chat_context.with(move |chat_message| { chat_context.with(move |chat_message| {
if let Some(message) = chat_message { if let Some(message) = chat_message {
update_chat_history(&set_chat_history, format!("{}\n", message.text)); chat_history.update(|history| history.push(format!("{}\n", message.text)));
} }
}) })
}); });
@ -59,34 +57,16 @@ pub fn Chat() -> impl IntoView {
Effect::new(move |_| { Effect::new(move |_| {
chat_update_context.with(move |chat_update| { chat_update_context.with(move |chat_update| {
if let Some(update) = chat_update { if let Some(update) = chat_update {
set_users(update.users.clone()); users.set(update.users.clone());
set_chat_name(update.room.clone()); chat_name.set(update.room.clone());
}
})
});
// Clear user list on disconnect
Effect::new(move |_| {
websocket.ready_state.with(move |status| {
if *status == ConnectionReadyState::Closed {
set_users(vec![]);
} }
}) })
}); });
// Handle sending messages // Handle sending messages
let send_message = move |_| { let send_message = move |_| {
if let Some(input) = chat_input_ref.get() { websocket.send(&to_string(&ChatMessage { text: chat_input() }).unwrap());
if input.value() != String::from("") { chat_input.set(String::new());
websocket.send(
&to_string(&ChatMessage {
text: input.value(),
})
.unwrap(),
);
input.set_value("");
}
}
}; };
// Keep chat scrolled to the bottom // Keep chat scrolled to the bottom
@ -102,34 +82,45 @@ pub fn Chat() -> impl IntoView {
view! { view! {
<div class="my-2"> <div class="my-2">
<h2 class="text-2xl">Chat: {move || chat_name()}</h2> <h2 class="text-2xl">Chat: {move || chat_name()}</h2>
<span class="flex"> <span class="flex justify-between">
<textarea <textarea
node_ref=chat_history_ref node_ref=chat_history_ref
class="w-96 h-60 font-mono rounded-sm resize-none bg-neutral-900 text-neutral-200" class="w-full h-60 p-1 font-mono rounded-md resize-none bg-neutral-900 text-neutral-200"
readonly=true readonly=true
wrap="soft" wrap="soft"
> >
{move || chat_history.get()} {move || chat_history.get()}
</textarea> </textarea>
<ul> <ul class="mx-2">
<h2 class="text-2xl">Users: {move || users().len()}</h2> <h2 class="text-2xl">Users: {move || users().len()}</h2>
{move || users().into_iter().map(|n| view! { <li>{n}</li> }).collect_view()} {move || users().into_iter().map(|n| view! { <li>{n}</li> }).collect_view()}
</ul> </ul>
</span> </span>
<br /> <br />
<span> <span>
<form onsubmit="return false" on:submit=send_message> <form onsubmit="return false" on:submit=send_message autocomplete="off">
<input <FieldContextProvider>
class="w-80 h-11 font-mono rounded-sm bg-neutral-900 text-neutral-200" <Field label="Message" name="message">
placeholder="talk shit..." <thaw::Input
node_ref=chat_input_ref rules=vec![InputRule::required(true.into())]
/> value=chat_input
<input placeholder="talk shit..."
class="py-2 px-4 pl-4 font-bold text-white rounded border-b-4 bg-neutral-600 border-neutral-800 hover:bg-neutral-700 hover:border-neutral-500" />
type="submit" </Field>
value="Send" <Button
disabled=move || !connected() button_type=ButtonType::Submit
/> on_click={
let field_context = FieldContextInjection::expect_context();
move |e: ev::MouseEvent| {
if !field_context.validate() {
e.prevent_default()
}
}
}
>
"Send"
</Button>
</FieldContextProvider>
</form> </form>
</span> </span>
</div> </div>

View file

@ -1,189 +0,0 @@
use crate::components::websocket::WebSocketContext;
use leptos::{html::Input, prelude::*};
use leptos_use::core::ConnectionReadyState;
use lib::*;
use serde_json::to_string;
use std::collections::BTreeSet;
#[component]
pub fn CreateGame() -> impl IntoView {
// Websocket stuff
let websocket = expect_context::<WebSocketContext>();
let (websocket_send, set_websocket_send) = signal("".to_string());
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
let tx = websocket.clone();
Effect::new(move |_| {
if websocket_send() != "".to_string() {
tx.send(&websocket_send());
}
});
// New game stuff
let card_packs = expect_context::<ReadSignal<CardPacksMeta>>();
let (show_packs, set_show_packs) = signal(false);
let (selected_packs, set_selected_packs) = signal::<BTreeSet<u8>>(BTreeSet::new());
Effect::new(move |_| {
set_selected_packs
.update(|set| set.extend(card_packs().official_meta.iter().map(|pack| pack.pack)));
});
Effect::new(move |_| {
set_selected_packs
.update(|set| set.extend(card_packs().unofficial_meta.iter().map(|pack| pack.pack)));
});
let new_game_name_ref = NodeRef::<Input>::new();
let toggle_show_packs = move |_| set_show_packs(!show_packs());
let request_new_game = move |_| {
if let Some(input) = new_game_name_ref.get() {
if input.value() == *"" {
println!("New game name is empty!");
} else if selected_packs().is_empty() {
println!("New game selected packs is empty!");
} else {
set_websocket_send(
to_string(&NewGameRequest {
name: input.value(),
packs: selected_packs().into_iter().collect::<Vec<_>>(),
})
.unwrap(),
);
input.set_value("");
}
}
};
view! {
<div class="my-2">
<h2 class="text-2xl">Create Game</h2>
<Show when=move || connected() fallback=|| view! { <p>"Disconnected."</p> }>
<div class="flex">
<form onsubmit="return false" on:submit=request_new_game>
<input
class="w-80 h-11 font-mono rounded-sm bg-neutral-900 text-neutral-200"
placeholder="Name"
disabled=move || !connected()
node_ref=new_game_name_ref
/>
<h2 class="text-2xl">Packs</h2>
<div class="p-2">
// <button type="button" class="bg-neutral-600">
// <input type="checkbox" id="official" checked />
// <label for="official">Official</label>
// </button>
// <button type="button" class="bg-neutral-600">
// <input type="checkbox" id="unofficial" checked />
// <label for="unofficial">Unofficial</label>
// </button>
<p>"All 205 card packs are enabled by default"</p>
<button type="button" class="bg-neutral-600" on:click=toggle_show_packs>
<label>Customize</label>
</button>
</div>
<Show when=move || show_packs()>
<span class="flex">
<div>
<h2 class="text-xl">Official</h2>
{move || {
card_packs()
.official_meta
.into_iter()
.map(|n| {
view! {
<input
type="checkbox"
value=n.pack
id=n.pack
checked
on:change=move |e| {
if event_target_checked(&e) {
set_selected_packs
.update(|packs| {
packs.insert(n.pack);
})
} else {
set_selected_packs
.update(|packs| {
packs.remove(&n.pack);
})
}
}
/>
<label for=n.pack>{n.name}</label>
<br />
// hax
{set_selected_packs
.update(|packs| {
packs.insert(n.pack);
})}
}
})
.collect_view()
}}
</div>
<div>
<h2 class="text-xl">Unofficial</h2>
{move || {
card_packs()
.unofficial_meta
.into_iter()
.map(|n| {
view! {
<input
checked
type="checkbox"
value=n.pack
id=n.pack
on:change=move |e| {
if event_target_checked(&e) {
set_selected_packs
.update(|packs| {
packs.insert(n.pack);
})
} else {
set_selected_packs
.update(|packs| {
packs.remove(&n.pack);
})
}
}
/>
<label for=n.pack>{n.name}</label>
<br />
// hax
{set_selected_packs
.update(|packs| {
packs.insert(n.pack);
})}
}
})
.collect_view()
}}
</div>
</span>
</Show>
<input
class="py-2 px-4 pl-4 font-bold text-white rounded border-b-4 bg-neutral-600 border-neutral-800 hover:bg-neutral-700 hover:border-neutral-500"
type="submit"
disabled=move || !connected()
value="New Game"
/>
</form>
</div>
</Show>
</div>
}
}

View file

@ -2,6 +2,7 @@ use crate::components::websocket::WebSocketContext;
use leptos::prelude::*; use leptos::prelude::*;
use leptos_use::core::ConnectionReadyState; use leptos_use::core::ConnectionReadyState;
use lib::*; use lib::*;
use thaw::*;
#[component] #[component]
pub fn Debug() -> impl IntoView { pub fn Debug() -> impl IntoView {
@ -14,7 +15,12 @@ pub fn Debug() -> impl IntoView {
// Websocket stuff // Websocket stuff
let status = move || websocket.ready_state.get().to_string(); let status = move || websocket.ready_state.get().to_string();
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open; let connected = RwSignal::new(false);
let disconnected = RwSignal::new(false);
Effect::new(move |_| {
connected.set(websocket.ready_state.get() == ConnectionReadyState::Open);
disconnected.set(websocket.ready_state.get() == ConnectionReadyState::Closed)
});
let open_connection = move |_| { let open_connection = move |_| {
(websocket.open)(); (websocket.open)();
}; };
@ -42,12 +48,12 @@ pub fn Debug() -> impl IntoView {
<p class="p-1">"Users Online: " {online_users}</p> <p class="p-1">"Users Online: " {online_users}</p>
<p class="p-1">"Active Games: " {active_games}</p> <p class="p-1">"Active Games: " {active_games}</p>
<div class="p-1"> <div class="p-1">
<button on:click=open_connection disabled=move || connected()> <Button on_click=open_connection disabled=connected>
"Connect" "Connect"
</button> </Button>
<button on:click=close_connection disabled=move || !connected()> <Button on_click=close_connection disabled=disconnected>
"Disconnect" "Disconnect"
</button> </Button>
</div> </div>
</div> </div>
} }

View file

@ -6,7 +6,7 @@ pub fn BlackCard() -> impl IntoView {
let game_meta = expect_context::<ReadSignal<Option<GameStateMeta>>>(); let game_meta = expect_context::<ReadSignal<Option<GameStateMeta>>>();
view! { view! {
<Show when=move || { game_meta().is_some() }> <Show when=move || { game_meta().is_some() }>
<div class="relative m-2 w-40 h-60 text-white bg-black rounded-lg"> <div class="relative m-2 w-40 h-60 text-white bg-black rounded-lg shadow-black shadow-md">
<p class="p-4">{game_meta().unwrap().black.0}</p> <p class="p-4">{game_meta().unwrap().black.0}</p>
<p class="absolute right-4 bottom-4">Pick: {game_meta().unwrap().black.1}</p> <p class="absolute right-4 bottom-4">Pick: {game_meta().unwrap().black.1}</p>
</div> </div>
@ -19,7 +19,7 @@ pub fn WhiteCard(card_data: WhiteCardMeta) -> impl IntoView {
let set_card_clicked = expect_context::<WriteSignal<String>>(); let set_card_clicked = expect_context::<WriteSignal<String>>();
view! { view! {
<div class="relative m-2 w-40 h-60 text-black bg-white rounded-lg"> <div class="relative m-2 w-40 h-60 text-black bg-white rounded-lg shadow-black drop-shadow-lg">
<p class="p-4">{card_data.text}</p> <p class="p-4">{card_data.text}</p>
<button <button
class="absolute w-full h-full opacity-10 left-0 top-0" class="absolute w-full h-full opacity-10 left-0 top-0"

View file

@ -3,6 +3,7 @@ use crate::components::websocket::WebSocketContext;
use leptos::prelude::*; use leptos::prelude::*;
use lib::*; use lib::*;
use serde_json::to_string; use serde_json::to_string;
use thaw::*;
#[component] #[component]
pub fn JudgingView() -> impl IntoView { pub fn JudgingView() -> impl IntoView {
@ -99,9 +100,13 @@ pub fn JudgingView() -> impl IntoView {
// Submit button // Submit button
<div class="w-full inline-flex flex-wrap justify-center"> <div class="w-full inline-flex flex-wrap justify-center">
<button type="button" on:click=submit_judge> <Button
appearance=ButtonAppearance::Secondary
button_type=ButtonType::Button
on_click=submit_judge
>
Submit Submit
</button> </Button>
</div> </div>
<Show <Show

View file

@ -4,6 +4,7 @@ use leptos::prelude::*;
use lib::*; use lib::*;
use serde_json::to_string; use serde_json::to_string;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use thaw::*;
#[component] #[component]
pub fn PlayingView() -> impl IntoView { pub fn PlayingView() -> impl IntoView {
@ -100,12 +101,14 @@ pub fn PlayingView() -> impl IntoView {
<div class="w-full inline-flex flex-wrap"> <div class="w-full inline-flex flex-wrap">
<BlackCard /> <BlackCard />
{move || selected_cards() {move || {
.into_iter() selected_cards()
.map(|card| { .into_iter()
view! { <WhiteCard card_data=card /> } .map(|card| {
}) view! { <WhiteCard card_data=card /> }
.collect_view()} })
.collect_view()
}}
</div> </div>
// Submit button // Submit button
@ -117,9 +120,13 @@ pub fn PlayingView() -> impl IntoView {
} }
> >
<button type="button" on:click=submit_move.clone()> <Button
Submit appearance=ButtonAppearance::Secondary
</button> button_type=ButtonType::Button
on_click=submit_move.clone()
>
"Submit"
</Button>
</Show> </Show>
</div> </div>

View file

@ -1,7 +1,6 @@
pub mod auth; pub mod auth;
pub mod browser; pub mod browser;
pub mod chat; pub mod chat;
pub mod create_game;
pub mod debug; pub mod debug;
pub mod game; pub mod game;
pub mod websocket; pub mod websocket;

View file

@ -1,8 +1,10 @@
use leptos::prelude::*; use leptos::prelude::*;
use leptos_meta::*;
use leptos_router::{ use leptos_router::{
components::{Route, Router, Routes}, components::{Route, Router, Routes},
StaticSegment, StaticSegment,
}; };
use thaw::*;
// Modules // Modules
mod components; mod components;
@ -14,11 +16,19 @@ use crate::pages::home::Home;
/// An app router which renders the homepage and handles 404's /// An app router which renders the homepage and handles 404's
#[component] #[component]
pub fn App() -> impl IntoView { pub fn App() -> impl IntoView {
let theme = RwSignal::new(Theme::dark());
provide_context(theme);
provide_meta_context();
view! { view! {
<Router> <ConfigProvider theme>
<Routes fallback=|| "Not found.".into_view()> <main class="min-h-screen">
<Route path=StaticSegment("") view=Home /> <Router>
</Routes> <Routes fallback=|| "Not found.".into_view()>
</Router> <Route path=StaticSegment("") view=Home />
</Routes>
</Router>
</main>
</ConfigProvider>
} }
} }

View file

@ -1,7 +1,6 @@
use crate::components::auth::*; use crate::components::auth::*;
use crate::components::browser::*; use crate::components::browser::*;
use crate::components::chat::*; use crate::components::chat::*;
use crate::components::create_game::*;
use crate::components::debug::*; use crate::components::debug::*;
use crate::components::game::*; use crate::components::game::*;
use crate::components::websocket::*; use crate::components::websocket::*;
@ -11,8 +10,36 @@ use thaw::*;
/// Default Home Page /// Default Home Page
#[component] #[component]
pub fn Home() -> impl IntoView { pub fn Home() -> impl IntoView {
let open = RwSignal::new(true); let modal = RwSignal::new(false);
let theme = RwSignal::new(Theme::dark());
// Suppress modal during development
if !cfg!(debug_assertions) {
modal.set(true);
};
let theme = expect_context::<RwSignal<Theme>>();
let icon = RwSignal::new(Some(icondata::BsMoon));
let on_click = move |_| {
icon.update(|icon| {
*icon = match icon {
Some(data) => {
if *data == icondata::BsMoon {
theme.set(Theme::light());
icondata::BsSun
} else {
theme.set(Theme::dark());
icondata::BsMoon
}
}
None => {
theme.set(Theme::dark());
icondata::BsMoon
}
}
.into();
});
};
view! { view! {
<ErrorBoundary fallback=|errors| { <ErrorBoundary fallback=|errors| {
@ -35,56 +62,65 @@ pub fn Home() -> impl IntoView {
}> }>
<div class="container m-auto"> <div class="container m-auto">
<h1 class="mx-4 text-6xl inter-med text-neutral-200">"Cards For Humanity"</h1> <div
<div class="p-5 bg-neutral-950 rounded-3xl shadow-black shadow-xl"> class="p-1 sm:p-5 sm:rounded-2xl sm:shadow-black sm:shadow-lg"
style="background-color: var(--colorNeutralBackground4);"
>
<div class="flex flex-wrap justify-between">
<h1 class="text-4xl sm:text-6xl md:text-7xl lg:text-8xl tracking-tighter">
"Cards For Humanity"
</h1>
<Button icon on_click appearance=ButtonAppearance::Transparent />
</div>
<ConfigProvider theme> <Dialog open=modal>
<Dialog open> <DialogSurface>
<DialogSurface> <DialogBody>
<DialogBody> <DialogTitle>"Hey!"</DialogTitle>
<DialogTitle>"Hey!"</DialogTitle> <DialogContent>
<DialogContent> <p class="indent-2 text-pretty">
<p> {"Welcome! Thank you for helping me test this. Please let me know about any issues you may come across. Chances are you already know how to contact me but in case you don't you can email me at "}
{"Welcome! Thank you for helping me test this. Please let me know about any issues you may come across. Chances are you already know how to contact me but in case you don't you can email me at "} <Link href="mailto:adam@doordesk.net">
<a href="mailto:adam@doordesk.net">adam@doordesk.net</a> adam@doordesk.net
{". The server may go down from time to time as bugs are found and as I add updates. If you manage to crash the server or notice it down for a long time please tell me about it."} </Link>
</p> {". The server may go down from time to time as bugs are found and as I add updates. If you manage to crash the server or notice it down for a long time please tell me about it."}
<br /> </p>
<p>Have fun!</p> <br />
</DialogContent> <p>Have fun!</p>
<DialogActions> </DialogContent>
<Button <DialogActions>
on_click=move |_| open.set(!open()) <Button
appearance=ButtonAppearance::Primary on_click=move |_| modal.set(false)
> appearance=ButtonAppearance::Primary
"Got it" >
</Button> "Got it"
</DialogActions> </Button>
</DialogBody> </DialogActions>
</DialogSurface> </DialogBody>
</Dialog> </DialogSurface>
</ConfigProvider> </Dialog>
<Websocket /> <Websocket />
<Auth /> <Auth />
<hr /> <Divider />
<Browser /> <Browser />
<hr /> <Divider />
<CreateGame />
<hr />
<Game /> <Game />
<hr /> <Divider />
<Chat /> <Chat />
<hr /> <Divider />
<Debug /> <Debug />
<hr /> <Divider />
<div class="my-2"> <div class="m-2">
<a href="https://git.doordesk.net/adam/cards/">git</a> <Link class="p-2" href="https://git.doordesk.net/adam/cards/">
"Git"
</Link>
<Link class="p-2" href="mailto:adam@doordesk.net">
"Email Me"
</Link>
</div> </div>
</div> </div>
</div> </div>
<br />
<br />
</ErrorBoundary> </ErrorBoundary>
} }
} }

View file

@ -1,4 +1,5 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashSet;
/// Judge decision /// Judge decision
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -82,7 +83,7 @@ pub struct GameBrowserMeta {
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CardPackMeta { pub struct CardPackMeta {
pub name: String, pub name: String,
pub pack: u8, pub pack: String,
pub num_white: usize, pub num_white: usize,
pub num_black: usize, pub num_black: usize,
} }
@ -137,5 +138,5 @@ pub struct ServerStateSummary {
pub struct NewGameRequest { pub struct NewGameRequest {
/// Game name /// Game name
pub name: String, pub name: String,
pub packs: Vec<u8>, pub packs: HashSet<String>,
} }

View file

@ -332,7 +332,11 @@ impl GameHandler {
let manifest = NewGameManifest { let manifest = NewGameManifest {
name: new_game.name, name: new_game.name,
host: host.clone(), host: host.clone(),
packs: new_game.packs, packs: new_game
.packs
.into_iter()
.map(|pack| u8::from_str_radix(&pack, 10).unwrap())
.collect(),
}; };
// Create game using manifest // Create game using manifest

View file

@ -201,7 +201,7 @@ pub fn load_cards_from_json(
// Start repackaging // Start repackaging
let meta = CardPackMeta { let meta = CardPackMeta {
name: sets.name, name: sets.name,
pack: pack.expect("No card pack number!"), pack: pack.expect("No card pack number!").to_string(),
num_white, num_white,
num_black, num_black,
}; };