From abe443e9c23abd528f83e624f5b84e057d76e7a2 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 11:56:04 -0400
Subject: [PATCH 001/119] basic leptos website
---
.env.example | 1 +
Cargo.lock | 1272 +++++++++++++++++-
Cargo.toml | 10 +
crates/website/.gitignore | 13 +
crates/website/Cargo.toml | 86 ++
crates/website/LICENSE | 22 +
crates/website/README.md | 67 +
crates/website/assets/favicon.ico | Bin 0 -> 15406 bytes
crates/website/end2end/package-lock.json | 74 +
crates/website/end2end/package.json | 13 +
crates/website/end2end/playwright.config.ts | 107 ++
crates/website/end2end/tests/example.spec.ts | 9 +
crates/website/src/app.rs | 63 +
crates/website/src/lib.rs | 21 +
crates/website/src/main.rs | 76 ++
crates/website/style/main.scss | 4 +
docker-compose.yml | 9 +
services/bot1/Dockerfile | 53 +
services/website/Dockerfile | 66 +
19 files changed, 1957 insertions(+), 9 deletions(-)
create mode 100644 crates/website/.gitignore
create mode 100644 crates/website/Cargo.toml
create mode 100644 crates/website/LICENSE
create mode 100644 crates/website/README.md
create mode 100644 crates/website/assets/favicon.ico
create mode 100644 crates/website/end2end/package-lock.json
create mode 100644 crates/website/end2end/package.json
create mode 100644 crates/website/end2end/playwright.config.ts
create mode 100644 crates/website/end2end/tests/example.spec.ts
create mode 100644 crates/website/src/app.rs
create mode 100644 crates/website/src/lib.rs
create mode 100644 crates/website/src/main.rs
create mode 100644 crates/website/style/main.scss
create mode 100644 services/bot1/Dockerfile
create mode 100644 services/website/Dockerfile
diff --git a/.env.example b/.env.example
index b0ad6bba..17686c51 100644
--- a/.env.example
+++ b/.env.example
@@ -57,3 +57,4 @@ REQUEST_TIMEOUT="3000"
#############################
IMAGE_BOT="circuitsacul/starboard-bot:latest"
IMAGE_BACKUP="circuitsacul/starboard-backup:latest"
+IMAGE_WEBSITE="circuitsacul/starboard-website:latest"
diff --git a/Cargo.lock b/Cargo.lock
index 2fff27bf..f27c152b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,210 @@
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "actix-codec"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8"
+dependencies = [
+ "bitflags 1.3.2",
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "memchr",
+ "pin-project-lite",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "actix-files"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d832782fac6ca7369a70c9ee9a20554623c5e51c76e190ad151780ebea1cf689"
+dependencies = [
+ "actix-http",
+ "actix-service",
+ "actix-utils",
+ "actix-web",
+ "askama_escape",
+ "bitflags 1.3.2",
+ "bytes",
+ "derive_more",
+ "futures-core",
+ "http-range",
+ "log",
+ "mime",
+ "mime_guess",
+ "percent-encoding",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "actix-http"
+version = "3.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74"
+dependencies = [
+ "actix-codec",
+ "actix-rt",
+ "actix-service",
+ "actix-utils",
+ "ahash 0.8.3",
+ "base64 0.21.2",
+ "bitflags 1.3.2",
+ "brotli",
+ "bytes",
+ "bytestring",
+ "derive_more",
+ "encoding_rs",
+ "flate2",
+ "futures-core",
+ "h2",
+ "http",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "language-tags",
+ "local-channel",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "rand",
+ "sha1",
+ "smallvec",
+ "tokio",
+ "tokio-util",
+ "tracing",
+ "zstd",
+]
+
+[[package]]
+name = "actix-macros"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
+dependencies = [
+ "quote",
+ "syn 2.0.28",
+]
+
+[[package]]
+name = "actix-router"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799"
+dependencies = [
+ "bytestring",
+ "http",
+ "regex",
+ "serde",
+ "tracing",
+]
+
+[[package]]
+name = "actix-rt"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e"
+dependencies = [
+ "futures-core",
+ "tokio",
+]
+
+[[package]]
+name = "actix-server"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327"
+dependencies = [
+ "actix-rt",
+ "actix-service",
+ "actix-utils",
+ "futures-core",
+ "futures-util",
+ "mio",
+ "num_cpus",
+ "socket2",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "actix-service"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a"
+dependencies = [
+ "futures-core",
+ "paste",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "actix-utils"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8"
+dependencies = [
+ "local-waker",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "actix-web"
+version = "4.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96"
+dependencies = [
+ "actix-codec",
+ "actix-http",
+ "actix-macros",
+ "actix-router",
+ "actix-rt",
+ "actix-server",
+ "actix-service",
+ "actix-utils",
+ "actix-web-codegen",
+ "ahash 0.7.6",
+ "bytes",
+ "bytestring",
+ "cfg-if",
+ "cookie",
+ "derive_more",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "http",
+ "itoa",
+ "language-tags",
+ "log",
+ "mime",
+ "once_cell",
+ "pin-project-lite",
+ "regex",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "smallvec",
+ "socket2",
+ "time 0.3.24",
+ "url",
+]
+
+[[package]]
+name = "actix-web-codegen"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9"
+dependencies = [
+ "actix-router",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "addr2line"
version = "0.20.0"
@@ -35,6 +239,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
dependencies = [
"cfg-if",
+ "getrandom",
"once_cell",
"version_check",
]
@@ -84,6 +289,18 @@ dependencies = [
"libc",
]
+[[package]]
+name = "anyhow"
+version = "1.0.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854"
+
+[[package]]
+name = "askama_escape"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
+
[[package]]
name = "async-io"
version = "1.13.0"
@@ -113,6 +330,17 @@ dependencies = [
"event-listener",
]
+[[package]]
+name = "async-recursion"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
+
[[package]]
name = "async-trait"
version = "0.1.72"
@@ -133,6 +361,34 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "attribute-derive"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c124f12ade4e670107b132722d0ad1a5c9790bcbc1b265336369ea05626b4498"
+dependencies = [
+ "attribute-derive-macro",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
+
+[[package]]
+name = "attribute-derive-macro"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b217a07446e0fb086f83401a98297e2d81492122f5874db5391bd270a185f88"
+dependencies = [
+ "collection_literals",
+ "interpolator",
+ "proc-macro-error",
+ "proc-macro-utils",
+ "proc-macro2",
+ "quote",
+ "quote-use",
+ "syn 2.0.28",
+]
+
[[package]]
name = "autocfg"
version = "1.1.0"
@@ -232,6 +488,15 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
+[[package]]
+name = "bytestring"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae"
+dependencies = [
+ "bytes",
+]
+
[[package]]
name = "cached"
version = "0.44.0"
@@ -304,6 +569,9 @@ name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+dependencies = [
+ "jobserver",
+]
[[package]]
name = "cfg-if"
@@ -327,10 +595,49 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "ciborium"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
+dependencies = [
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
+]
+
+[[package]]
+name = "ciborium-io"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
+
+[[package]]
+name = "ciborium-ll"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
+dependencies = [
+ "ciborium-io",
+ "half",
+]
+
+[[package]]
+name = "collection_literals"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271"
+
[[package]]
name = "common"
version = "0.1.0"
+[[package]]
+name = "common_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3f6d59c71e7dc3af60f0af9db32364d96a16e9310f3f5db2b55ed642162dd35"
+
[[package]]
name = "concurrent-queue"
version = "2.2.0"
@@ -340,6 +647,81 @@ dependencies = [
"crossbeam-utils",
]
+[[package]]
+name = "config"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d379af7f68bfc21714c6c7dea883544201741d2ce8274bb12fa54f89507f52a7"
+dependencies = [
+ "async-trait",
+ "json5",
+ "lazy_static",
+ "nom",
+ "pathdiff",
+ "ron",
+ "rust-ini",
+ "serde",
+ "serde_json",
+ "toml",
+ "yaml-rust",
+]
+
+[[package]]
+name = "console_error_panic_hook"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "const_format"
+version = "0.2.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c990efc7a285731f9a4378d81aff2f0e85a2c8781a05ef0f8baa8dac54d0ff48"
+dependencies = [
+ "const_format_proc_macros",
+]
+
+[[package]]
+name = "const_format_proc_macros"
+version = "0.2.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e026b6ce194a874cb9cf32cd5772d1ef9767cc8fcb5765948d74f37a9d8b2bf6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "convert_case"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+
+[[package]]
+name = "convert_case"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "cookie"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
+dependencies = [
+ "percent-encoding",
+ "time 0.3.24",
+ "version_check",
+]
+
[[package]]
name = "core-foundation"
version = "0.9.3"
@@ -580,14 +962,27 @@ dependencies = [
"serde",
]
+[[package]]
+name = "derive-where"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bc1955a640c4464859ae700fbe48e666da6fdce99ce5fe1acd08dd295889d10"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
+
[[package]]
name = "derive_more"
version = "0.99.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [
+ "convert_case 0.4.0",
"proc-macro2",
"quote",
+ "rustc_version",
"syn 1.0.109",
]
@@ -622,6 +1017,12 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "dlv-list"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
+
[[package]]
name = "doc-comment"
version = "0.3.3"
@@ -640,6 +1041,24 @@ version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
+[[package]]
+name = "drain_filter_polyfill"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408"
+
+[[package]]
+name = "educe"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "079044df30bb07de7d846d41a184c4b00e66ebdac93ee459253474f3a47e50ae"
+dependencies = [
+ "enum-ordinalize",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "either"
version = "1.9.0"
@@ -667,6 +1086,25 @@ dependencies = [
"cfg-if",
]
+[[package]]
+name = "enum-ordinalize"
+version = "3.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4f76552f53cefc9a7f64987c3701b99d982f7690606fd67de1d09712fbf52f1"
+dependencies = [
+ "num-bigint",
+ "num-traits",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
[[package]]
name = "errno"
version = "0.3.2"
@@ -928,8 +1366,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
]
[[package]]
@@ -944,6 +1384,39 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+[[package]]
+name = "gloo-net"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-sink",
+ "gloo-utils",
+ "js-sys",
+ "pin-project",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-utils"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e"
+dependencies = [
+ "js-sys",
+ "serde",
+ "serde_json",
+ "wasm-bindgen",
+ "web-sys",
+]
+
[[package]]
name = "h2"
version = "0.3.20"
@@ -956,24 +1429,36 @@ dependencies = [
"futures-sink",
"futures-util",
"http",
- "indexmap",
+ "indexmap 1.9.3",
"slab",
"tokio",
"tokio-util",
"tracing",
]
+[[package]]
+name = "half"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
+
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+dependencies = [
+ "ahash 0.7.6",
+]
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
+dependencies = [
+ "ahash 0.8.3",
+]
[[package]]
name = "hashbrown"
@@ -1044,6 +1529,15 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "html-escape"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476"
+dependencies = [
+ "utf8-width",
+]
+
[[package]]
name = "http"
version = "0.2.9"
@@ -1066,6 +1560,12 @@ dependencies = [
"pin-project-lite",
]
+[[package]]
+name = "http-range"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
+
[[package]]
name = "httparse"
version = "1.8.0"
@@ -1185,6 +1685,16 @@ dependencies = [
"serde",
]
+[[package]]
+name = "indexmap"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.0",
+]
+
[[package]]
name = "instant"
version = "0.1.12"
@@ -1194,6 +1704,18 @@ dependencies = [
"cfg-if",
]
+[[package]]
+name = "interpolator"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8"
+
+[[package]]
+name = "inventory"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a53088c87cf71c9d4f3372a2cb9eea1e7b8a0b1bf8b7f7d23fe5b76dbb07e63b"
+
[[package]]
name = "io-lifetimes"
version = "1.0.11"
@@ -1226,6 +1748,15 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
+[[package]]
+name = "jobserver"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "js-sys"
version = "0.3.64"
@@ -1235,12 +1766,248 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "json5"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
+dependencies = [
+ "pest",
+ "pest_derive",
+ "serde",
+]
+
+[[package]]
+name = "language-tags"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
+
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+[[package]]
+name = "leptos"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d08fd7674758f996050217a8aff9e584d033c2e5c882cd3f52fb5090dc361dd"
+dependencies = [
+ "cfg-if",
+ "leptos_config",
+ "leptos_dom",
+ "leptos_macro",
+ "leptos_reactive",
+ "leptos_server",
+ "server_fn",
+ "tracing",
+ "typed-builder",
+]
+
+[[package]]
+name = "leptos_actix"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c122547e0a04d6b2efaef999b3165f03eb1b1284fdb298f05bde9107ed16ec2"
+dependencies = [
+ "actix-http",
+ "actix-web",
+ "futures",
+ "leptos",
+ "leptos_integration_utils",
+ "leptos_meta",
+ "leptos_router",
+ "parking_lot 0.12.1",
+ "regex",
+ "serde_json",
+ "tracing",
+]
+
+[[package]]
+name = "leptos_config"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e5c13a1ae92b5a545cc013205288751fb2fef521de5a092067fd8429ad343e8"
+dependencies = [
+ "config",
+ "regex",
+ "serde",
+ "thiserror",
+ "typed-builder",
+]
+
+[[package]]
+name = "leptos_dom"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35994afab1dca68a46c7b40a29d40d84a2e06e1b1fa0d5c5915ade4f4f2611ee"
+dependencies = [
+ "async-recursion",
+ "cfg-if",
+ "drain_filter_polyfill",
+ "educe",
+ "futures",
+ "getrandom",
+ "html-escape",
+ "indexmap 2.0.0",
+ "itertools",
+ "js-sys",
+ "leptos_reactive",
+ "once_cell",
+ "pad-adapter",
+ "paste",
+ "rustc-hash",
+ "serde_json",
+ "server_fn",
+ "smallvec",
+ "tracing",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "leptos_hot_reload"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a088a4dd5489941a9cc73719148f217c78f0d761a50e025739653c3b7f9d484"
+dependencies = [
+ "anyhow",
+ "camino",
+ "indexmap 2.0.0",
+ "parking_lot 0.12.1",
+ "proc-macro2",
+ "quote",
+ "rstml",
+ "serde",
+ "syn 2.0.28",
+ "walkdir",
+]
+
+[[package]]
+name = "leptos_integration_utils"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfd4a097f1870172f5079e44af99fb5d5f02cd856db6b32a6ac98cc58f1a1f47"
+dependencies = [
+ "futures",
+ "leptos",
+ "leptos_config",
+ "leptos_hot_reload",
+ "leptos_meta",
+ "tracing",
+]
+
+[[package]]
+name = "leptos_macro"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bdd7a21d20ca21bb12d67d050d4b0ad9973b156bce98f499f8b1789f11959dd"
+dependencies = [
+ "attribute-derive",
+ "cfg-if",
+ "convert_case 0.6.0",
+ "html-escape",
+ "itertools",
+ "leptos_hot_reload",
+ "prettyplease",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "rstml",
+ "server_fn_macro",
+ "syn 2.0.28",
+ "tracing",
+ "uuid",
+]
+
+[[package]]
+name = "leptos_meta"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed4e4855b6d0047f1cdbf0e9d41b76a1b596ec374f844d2bae1e48f2d2df70d8"
+dependencies = [
+ "cfg-if",
+ "indexmap 2.0.0",
+ "leptos",
+ "tracing",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "leptos_reactive"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5500318e457b4ab841722a5988e8db0def1ee7ac66b816ba9073c100c4984a"
+dependencies = [
+ "base64 0.21.2",
+ "cfg-if",
+ "futures",
+ "indexmap 2.0.0",
+ "js-sys",
+ "rustc-hash",
+ "self_cell",
+ "serde",
+ "serde-wasm-bindgen",
+ "serde_json",
+ "slotmap",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "leptos_router"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57a6cd29a56992923c9bad3c814ab9d7a78bf0bfec80c8f4dfbf049144fa5828"
+dependencies = [
+ "cached",
+ "cfg-if",
+ "common_macros",
+ "gloo-net",
+ "js-sys",
+ "lazy_static",
+ "leptos",
+ "linear-map",
+ "log",
+ "lru",
+ "once_cell",
+ "percent-encoding",
+ "regex",
+ "serde",
+ "serde_json",
+ "serde_qs",
+ "thiserror",
+ "tracing",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "leptos_server"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28d958deee3c7ffda892a67ac4a47500aebbaf00b11d217cfe6fd494c297818"
+dependencies = [
+ "inventory",
+ "lazy_static",
+ "leptos_macro",
+ "leptos_reactive",
+ "serde",
+ "server_fn",
+ "thiserror",
+ "tracing",
+]
+
[[package]]
name = "libc"
version = "0.2.147"
@@ -1258,6 +2025,22 @@ dependencies = [
"vcpkg",
]
+[[package]]
+name = "linear-map"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee"
+dependencies = [
+ "serde",
+ "serde_test",
+]
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
@@ -1270,6 +2053,24 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
+[[package]]
+name = "local-channel"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "local-waker",
+]
+
+[[package]]
+name = "local-waker"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1"
+
[[package]]
name = "lock_api"
version = "0.4.10"
@@ -1286,6 +2087,15 @@ version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
+[[package]]
+name = "lru"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670"
+dependencies = [
+ "hashbrown 0.13.2",
+]
+
[[package]]
name = "mach"
version = "0.3.2"
@@ -1349,6 +2159,16 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+[[package]]
+name = "mime_guess"
+version = "2.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@@ -1371,6 +2191,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [
"libc",
+ "log",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys",
]
@@ -1441,6 +2262,27 @@ dependencies = [
"minimal-lexical",
]
+[[package]]
+name = "num-bigint"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
[[package]]
name = "num-traits"
version = "0.2.16"
@@ -1528,6 +2370,16 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "ordered-multimap"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a"
+dependencies = [
+ "dlv-list",
+ "hashbrown 0.12.3",
+]
+
[[package]]
name = "os_info"
version = "3.7.0"
@@ -1539,6 +2391,12 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "pad-adapter"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56d80efc4b6721e8be2a10a5df21a30fa0b470f1539e53d8b4e6e75faf938b63"
+
[[package]]
name = "parking"
version = "2.1.0"
@@ -1594,16 +2452,66 @@ dependencies = [
]
[[package]]
-name = "paste"
-version = "1.0.14"
+name = "paste"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
+
+[[package]]
+name = "pathdiff"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
+
+[[package]]
+name = "pest"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a"
+dependencies = [
+ "thiserror",
+ "ucd-trie",
+]
+
+[[package]]
+name = "pest_derive"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853"
+dependencies = [
+ "pest",
+ "pest_generator",
+]
+
+[[package]]
+name = "pest_generator"
+version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
+checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929"
+dependencies = [
+ "pest",
+ "pest_meta",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
[[package]]
-name = "percent-encoding"
-version = "2.3.0"
+name = "pest_meta"
+version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
+checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48"
+dependencies = [
+ "once_cell",
+ "pest",
+ "sha2",
+]
[[package]]
name = "phf"
@@ -1623,6 +2531,26 @@ dependencies = [
"siphasher",
]
+[[package]]
+name = "pin-project"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
+
[[package]]
name = "pin-project-lite"
version = "0.2.10"
@@ -1669,6 +2597,51 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+[[package]]
+name = "prettyplease"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.28",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-utils"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f59e109e2f795a5070e69578c4dc101068139f74616778025ae1011d4cd41a8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "smallvec",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.66"
@@ -1678,6 +2651,19 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "proc-macro2-diagnostics"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+ "version_check",
+ "yansi",
+]
+
[[package]]
name = "psutil"
version = "3.2.2"
@@ -1733,6 +2719,18 @@ dependencies = [
"proc-macro2",
]
+[[package]]
+name = "quote-use"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58e9a38ef862d7fec635661503289062bc5b3035e61859a8de3d3f81823accd2"
+dependencies = [
+ "derive-where",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
+
[[package]]
name = "rand"
version = "0.8.5"
@@ -1882,18 +2880,59 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "ron"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a"
+dependencies = [
+ "base64 0.13.1",
+ "bitflags 1.3.2",
+ "serde",
+]
+
+[[package]]
+name = "rstml"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6522514806fbc2fc4c3d54ee9cc01e928fa00e1c988af4c730a64f57637ad7cf"
+dependencies = [
+ "proc-macro2",
+ "proc-macro2-diagnostics",
+ "quote",
+ "syn 2.0.28",
+ "syn_derive",
+ "thiserror",
+]
+
[[package]]
name = "rust-fuzzy-search"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2"
+[[package]]
+name = "rust-ini"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df"
+dependencies = [
+ "cfg-if",
+ "ordered-multimap",
+]
+
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
[[package]]
name = "rustc_version"
version = "0.4.0"
@@ -2035,6 +3074,12 @@ dependencies = [
"libc",
]
+[[package]]
+name = "self_cell"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6"
+
[[package]]
name = "semver"
version = "1.0.18"
@@ -2171,6 +3216,17 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde-wasm-bindgen"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e"
+dependencies = [
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
[[package]]
name = "serde_derive"
version = "1.0.180"
@@ -2193,6 +3249,17 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_qs"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c"
+dependencies = [
+ "percent-encoding",
+ "serde",
+ "thiserror",
+]
+
[[package]]
name = "serde_repr"
version = "0.1.16"
@@ -2204,6 +3271,15 @@ dependencies = [
"syn 2.0.28",
]
+[[package]]
+name = "serde_test"
+version = "1.0.176"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@@ -2225,7 +3301,7 @@ dependencies = [
"base64 0.21.2",
"chrono",
"hex",
- "indexmap",
+ "indexmap 1.9.3",
"serde",
"serde_json",
"serde_with_macros",
@@ -2244,6 +3320,56 @@ dependencies = [
"syn 2.0.28",
]
+[[package]]
+name = "server_fn"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "644216cf54c944da2d7fc7a75337a35dc39de19130be3fd88fd58674719a1b5b"
+dependencies = [
+ "ciborium",
+ "const_format",
+ "gloo-net",
+ "inventory",
+ "js-sys",
+ "lazy_static",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "serde_qs",
+ "server_fn_macro_default",
+ "syn 2.0.28",
+ "thiserror",
+ "xxhash-rust",
+]
+
+[[package]]
+name = "server_fn_macro"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1db2cd1a054f5c6ec168982241f6cdad083591d6c68449e666c839ec421bfc54"
+dependencies = [
+ "const_format",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "syn 2.0.28",
+ "xxhash-rust",
+]
+
+[[package]]
+name = "server_fn_macro_default"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35ee7b18c66e7a30b1855096cee24d540925825ce91193f42fae322033b109c1"
+dependencies = [
+ "server_fn_macro",
+ "syn 2.0.28",
+]
+
[[package]]
name = "sha1"
version = "0.10.5"
@@ -2305,6 +3431,16 @@ dependencies = [
"autocfg",
]
+[[package]]
+name = "slotmap"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
+dependencies = [
+ "serde",
+ "version_check",
+]
+
[[package]]
name = "smallvec"
version = "1.11.0"
@@ -2398,7 +3534,7 @@ dependencies = [
"hex",
"hkdf",
"hmac",
- "indexmap",
+ "indexmap 1.9.3",
"itoa",
"libc",
"log",
@@ -2540,6 +3676,18 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "syn_derive"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8128874d02f9a114ade6d9ad252078cb32d3cb240e26477ac73d7e9c495c605e"
+dependencies = [
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.28",
+]
+
[[package]]
name = "tagptr"
version = "0.2.0"
@@ -2732,6 +3880,15 @@ dependencies = [
"tracing",
]
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "tower-service"
version = "0.3.2"
@@ -2745,6 +3902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
+ "log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@@ -2953,12 +4111,29 @@ dependencies = [
"twilight-model",
]
+[[package]]
+name = "typed-builder"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64cba322cb9b7bc6ca048de49e83918223f35e7a86311267013afff257004870"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
+[[package]]
+name = "ucd-trie"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
+
[[package]]
name = "uname"
version = "0.1.1"
@@ -3010,6 +4185,12 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
+[[package]]
+name = "unicode-xid"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
+
[[package]]
name = "unicode_categories"
version = "0.1.1"
@@ -3053,6 +4234,12 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
+[[package]]
+name = "utf8-width"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1"
+
[[package]]
name = "uuid"
version = "1.4.1"
@@ -3213,6 +4400,22 @@ dependencies = [
"webpki",
]
+[[package]]
+name = "website"
+version = "0.1.0"
+dependencies = [
+ "actix-files",
+ "actix-web",
+ "cfg-if",
+ "console_error_panic_hook",
+ "http",
+ "leptos",
+ "leptos_actix",
+ "leptos_meta",
+ "leptos_router",
+ "wasm-bindgen",
+]
+
[[package]]
name = "whoami"
version = "1.4.1"
@@ -3337,3 +4540,54 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
+
+[[package]]
+name = "xxhash-rust"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "735a71d46c4d68d71d4b24d03fdc2b98e38cea81730595801db779c04fe80d70"
+
+[[package]]
+name = "yaml-rust"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
+dependencies = [
+ "linked-hash-map",
+]
+
+[[package]]
+name = "yansi"
+version = "1.0.0-rc"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ee746ad3851dd3bc40e4a028ab3b00b99278d929e48957bcb2d111874a7e43e"
+
+[[package]]
+name = "zstd"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "6.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581"
+dependencies = [
+ "libc",
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.8+zstd.1.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 5c8dcac9..4ce04e12 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,17 @@
resolver = "2"
members = [
"crates/starboard",
+ "crates/website",
"crates/common",
"crates/database",
"crates/errors",
]
+
+# Defines a size-optimized profile for the WASM bundle in release mode
+# this is used for the website
+[profile.wasm-release]
+inherits = "release"
+opt-level = 'z'
+lto = true
+codegen-units = 1
+panic = "abort"
diff --git a/crates/website/.gitignore b/crates/website/.gitignore
new file mode 100644
index 00000000..8cdaa33d
--- /dev/null
+++ b/crates/website/.gitignore
@@ -0,0 +1,13 @@
+# Generated by Cargo
+# will have compiled files and executables
+/target/
+pkg
+
+# These are backup files generated by rustfmt
+**/*.rs.bk
+
+# node e2e test tools and outputs
+node_modules/
+test-results/
+end2end/playwright-report/
+playwright/.cache/
diff --git a/crates/website/Cargo.toml b/crates/website/Cargo.toml
new file mode 100644
index 00000000..f6bda04e
--- /dev/null
+++ b/crates/website/Cargo.toml
@@ -0,0 +1,86 @@
+[package]
+name = "website"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+
+[dependencies]
+actix-files = { version = "0.6", optional = true }
+actix-web = { version = "4", optional = true, features = ["macros"] }
+console_error_panic_hook = "0.1"
+cfg-if = "1"
+http = { version = "0.2", optional = true }
+leptos = { version = "0.4", features = ["nightly"] }
+leptos_meta = { version = "0.4", features = ["nightly"] }
+leptos_actix = { version = "0.4", optional = true }
+leptos_router = { version = "0.4", features = ["nightly"] }
+wasm-bindgen = "=0.2.87"
+
+[features]
+csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
+hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
+ssr = [
+ "dep:actix-files",
+ "dep:actix-web",
+ "dep:leptos_actix",
+ "leptos/ssr",
+ "leptos_meta/ssr",
+ "leptos_router/ssr",
+]
+
+[package.metadata.leptos]
+# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
+output-name = "website"
+# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup.
+site-root = "target/site"
+# The site-root relative folder where all compiled output (JS, WASM and CSS) is written
+# Defaults to pkg
+site-pkg-dir = "pkg"
+# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to //app.css
+style-file = "style/main.scss"
+# Assets source dir. All files found here will be copied and synchronized to site-root.
+# The assets-dir cannot have a sub directory with the same name/path as site-pkg-dir.
+#
+# Optional. Env: LEPTOS_ASSETS_DIR.
+assets-dir = "assets"
+# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
+site-addr = "127.0.0.1:3000"
+# The port to use for automatic reload monitoring
+reload-port = 3001
+# [Optional] Command to use when running end2end tests. It will run in the end2end dir.
+# [Windows] for non-WSL use "npx.cmd playwright test"
+# This binary name can be checked in Powershell with Get-Command npx
+end2end-cmd = "npx playwright test"
+end2end-dir = "end2end"
+# The browserlist query used for optimizing the CSS.
+browserquery = "defaults"
+# Set by cargo-leptos watch when building with that tool. Controls whether autoreload JS will be included in the head
+watch = false
+# The environment Leptos will run in, usually either "DEV" or "PROD"
+env = "DEV"
+# The features to use when compiling the bin target
+#
+# Optional. Can be over-ridden with the command line parameter --bin-features
+bin-features = ["ssr"]
+
+# If the --no-default-features flag should be used when compiling the bin target
+#
+# Optional. Defaults to false.
+bin-default-features = false
+
+# The features to use when compiling the lib target
+#
+# Optional. Can be over-ridden with the command line parameter --lib-features
+lib-features = ["hydrate"]
+
+# If the --no-default-features flag should be used when compiling the lib target
+#
+# Optional. Defaults to false.
+lib-default-features = false
+
+# The profile to use for the lib target when compiling for release
+#
+# Optional. Defaults to "release".
+lib-profile-release = "wasm-release"
diff --git a/crates/website/LICENSE b/crates/website/LICENSE
new file mode 100644
index 00000000..0aed6357
--- /dev/null
+++ b/crates/website/LICENSE
@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) 2022 henrik
+Copyright (c) 2023-present CircuitSacul
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/crates/website/README.md b/crates/website/README.md
new file mode 100644
index 00000000..53075464
--- /dev/null
+++ b/crates/website/README.md
@@ -0,0 +1,67 @@
+
+
+
+
+
+# Leptos Starter Template
+
+This is a template for use with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool.
+
+## Creating your template repo
+
+If you don't have `cargo-leptos` installed you can install it with
+
+`cargo install cargo-leptos`
+
+Then run
+
+`cargo leptos new --git leptos-rs/start`
+
+to generate a new project template.
+
+`cd {projectname}`
+
+to go to your newly created project.
+
+Of course, you should explore around the project structure, but the best place to start with your application code is in `src/app.rs`.
+
+## Running your project
+
+`cargo leptos watch`
+
+## Installing Additional Tools
+
+By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools.
+
+1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly
+2. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly
+3. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future)
+4. `npm install -g sass` - install `dart-sass` (should be optional in future)
+
+## Executing a Server on a Remote Machine Without the Toolchain
+After running a `cargo leptos build --release` the minimum files needed are:
+
+1. The server binary located in `target/server/release`
+2. The `site` directory and all files within located in `target/site`
+
+Copy these files to your remote server. The directory structure should be:
+```text
+leptos_start
+site/
+```
+Set the following environment variables (updating for your project as needed):
+```sh
+export LEPTOS_OUTPUT_NAME="leptos_start"
+export LEPTOS_SITE_ROOT="site"
+export LEPTOS_SITE_PKG_DIR="pkg"
+export LEPTOS_SITE_ADDR="127.0.0.1:3000"
+export LEPTOS_RELOAD_PORT="3001"
+```
+Finally, run the server binary.
+
+## Notes about CSR and Trunk:
+Although it is not recommended, you can also run your project without server integration using the feature `csr` and `trunk serve`:
+
+`trunk serve --open --features csr`
+
+This may be useful for integrating external tools which require a static site, e.g. `tauri`.
diff --git a/crates/website/assets/favicon.ico b/crates/website/assets/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..2ba8527cb12f5f28f331b8d361eef560492d4c77
GIT binary patch
literal 15406
zcmeHOd3aPs5`TblWD*3D%tXPJ#q(n!z$P=3gCjvf#a)E}a;Uf>h{pmVih!a-5LVO`
zB?JrzEFicD0wRLo0iPfO372xnkvkzFlRHB)lcTnNZ}KK@US{UKN#b8?e_zkLy1RZ=
zT~*y(-6IICgf>E_P6A)M3(wvl2qr-gx_5Ux-_uzT*6_Q&ee1v9B?vzS3&K5IhO2N5
z$9ukLN<`G>$$|GLnga~y%>f}*j%+w@(ixVUb^1_Gjoc;(?TrD3m2)RduFblVN)uy;
zQAEd^T{5>-YYH%|Kv{V^cxHMBr1Ik7Frht$imC`rqx@5*|
z+OqN!xAjqmaU=qR$uGDMa7p!W9oZ+64($4xDk^FyFQ<_9Z`(;DLnB<;LLJD1<&vnZ
zo0(>zIkQTse}qNMb6+i`th54(3pKm8;UAJ<_BULR*Z=m5FU7jiW(l+}WkHZ|e@1
z`pm;Q^pCuLUQUrnQ(hPM10pSSHQS=Bf8DqG1&!-B!oQQ|FuzLruL1w(+g<8&znyI?
zzX-}?SwUvNjEuT?7uUOy{Fb@xKklpj+jdYM^IK9}NxvLRZd{l9FHEQJ4IO~q%4I0O
zAN|*8x^nIU4Giw?f*tmNx=7H)2-Zn?J^B6SgpcW3ZXV_57Sn%Mtfr_=w|sYpAhdJT
zcKo6Z*oIOU(az~3$LOEWm9Q)dYWMA}T7L23MVGqrcA%4H)+^`+=j+Hh8CTCnnG2Rh
zgcXVW%F8$R9)6}f=NQiLPt8qt3xNUQI>Q*)H1lzk<&n?XR-f}tc&9V0H0lhGqHJ^N
zN%h(9-Of2_)!Xk{qdIkU>1%mk%I_Id1!MU*yq&&>)Q+!L^t&-2mW9Xq7g9C@*
zl&PKJ&su2L+iku?Te?Pf?k3tUK){Bj_gb&aPo8Ago^XI~mRTd(5{&^tf1)!-lSMha
z@$~ae!r(~`=p&|mMxy2EiZQ6FvXb(1avS*`Pj%$)*?vwceGKHmHnl`v&fEQ_Wh+G)
zEPQ^3&oV%}%;zF`AM|S%d>pM@1}33PN5*4SewROk_K$n^i8QjaYiRzwG8#OvVIF|{x85wH+?*P*%)woI
zR538k@=(E`V;p1UwA|fqSh`$n_t;Sz4T)`_s~pRR4lbmWWSdxa-FqLZ%fLT)Bh?iye?COx~mO1wkn5)HNMg7`8~
z25VJhz&3Z7`M>6luJrEw$Jikft+6SxyIh?)PU1?DfrKMGC
z=3T;;omE4H`PWqF8?0*dOA3o9y@~WK`S}{?tIHquEw?v`M^D%Lobpdrp%3}1=-&qk
zqAtb1px-1Fy6}E8IUg4s%8B0~P<P5C;de%@n~XnDKF@fr$a+^@$^P|>vlw($aSK2lRtLt~8tRb`I0
znfI!G?K|<5ry*gk>y56rZy0NkK6)))6Mg1=K?7yS9p+#1Ij=W*%5Rt-mlc;#MOnE9
zoi`-+6oj@)`gq2Af!B+9%J#K9V=ji2dj2<_qaLSXOCeqQ&<0zMSb$5mAi;HU=v`v<>NYk}MbD!ewYVB+N-ctzn=l&bTwv)*7
zmY<+Y@SBbtl9PPk$HTR?ln@(T92XjTRj0Mx|Mzl;lW>Su_y^~fh?8(L?oz8h!cCpb
zZG-OY=NJ3{>r*`U<(J%#zjFT-a9>u6+23H{=d(utkgqt7@^)C;pkb)fQ|Q=*8*SyT
z;otKe+f8fEp)ZacKZDn3TNzs>_Kx+g*c_mr8LBhr8GnoEmAQk#%sR52`bdbW8Ms$!0u2bdt=T-lK3JbDW`F(Urt%Ob2seiN>7U`YN}aOdIiCC;eeufJC#m3S
z9#|l2c?G@t*hH5y^76jkv)rs4H+;oiTuY5FQwRMN_7NUqeiD|b&RyxPXQz|3qC(_>
zZJMwjC4F!1m2INXqzisQ4X^w=>&(+Ecdu&~IWEMn7f*YcYI&eWI(6hI#f114%aymM
zyhlG6{q>XN7(LyGiMAS&qijR%d2rV|>AUT_sE&EKUSTCM26>aKzNxk0?K|utOcxl#
zxIOwM#O!!H+QzbX*&p=QuKe4y;bS>&StQOE5AEGg_ubk8{;1yOVAJfE_Js-lL7rr9
z)CEuFIlkApj~uV^zJK7KocjT=4B
zJP(}0x}|A7C$$5gIp>KBPZ|A#2Ew;$#g9Fk)r;Q~?G$>x<+JM)J3u>j
zi68K=I;ld`JJ?Nq+^_B?C+Q%+x#m{9JF$tbaDeNIep%=^#>KHGtg=L)>m
z_J&vaZTs2{qP!4Gdw5u5Kcf}5R4(q}Lebx%(J$7l*Q`Il#pCTM%!`y5y*-~zIVs}D
z9;t+(xmV~R65^ZQXe+<5{$QW0O8MT~a{kdFLR)nfRMA9L(YU>x*DTltN#m-2km
zC;T`cfb{c`mcx(z7o_a8bYJn8_^dz4Cq!DZ37{P6uF{@#519UWK1{>(9sZB1I^6MmNc39MJ-_|)!S8vO+O3&$MulU3Gc
z_W{N*B(yneyl-oN_MKaJ{CZ6dv-~^8uPbLSh&0jfV@EfA{2Dc!_rOyfx`R0T@LonA
z<*%O?-aa_Wm-z$s@K(ex7UhM0-?9C=PkYdk&d2n((E4>&(f4D`fOQY%CURMMyJyU`
zVeJBAId&StHjw76tnwSqZs3e0683`L{a3k9JYdg#(ZVw4J`&CkV-2LFaDE1Z?CehVy%vZx$tM3tTax8E@2;N^QTrPcI?Ob8uK!DM0_sfE6ks2M?iw
zPS4{(k-PF*-oY>S!d9;L+|xdTtLen9B2LvpL4k;#ScB<
z$NP_7j~7)5eXuoYEk*dK_rSz9yT_C4B{r~^#^o}-VQI=Y?01|$aa!a7=UEm$|DsQQ
zfLK1qmho2@)nwA?$1%T6jwO2HZ({6&;`s|OQOxI4S8*Hw=Qp!b(gNJR%SAj&wGa>^&2@x)Vj
zhd^WfzJ^b0O{E^q82Pw({uT`E`MT2WnZ02{E%t*yRPN>?W>0vU^4@Vyh4;mLj918c
z*s*papo?<}cQM{5lcgZScx}?usg{mS!KkH9U%@|^_33?{FI{1ss+8kXyFY&5M-e~f
zM$){FF;_+z3sNJ)Er~{Beux$fEl{R4|7WKcpEsGtK57f+H0DJ$hI;U;JtF>+lG@sV
zQI_;bQ^7XIJ>Bs?C32b1v;am;P4GUqAJ#zOHv}4SmV|xXX6~O9&e_~YCCpbT>s$`!
k<4FtN!5=14"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "18.11.9",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz",
+ "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==",
+ "dev": true
+ },
+ "node_modules/playwright-core": {
+ "version": "1.28.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz",
+ "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==",
+ "dev": true,
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ }
+ },
+ "dependencies": {
+ "@playwright/test": {
+ "version": "1.28.0",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz",
+ "integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*",
+ "playwright-core": "1.28.0"
+ }
+ },
+ "@types/node": {
+ "version": "18.11.9",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz",
+ "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==",
+ "dev": true
+ },
+ "playwright-core": {
+ "version": "1.28.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz",
+ "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==",
+ "dev": true
+ }
+ }
+}
diff --git a/crates/website/end2end/package.json b/crates/website/end2end/package.json
new file mode 100644
index 00000000..ed785859
--- /dev/null
+++ b/crates/website/end2end/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "end2end",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {},
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "@playwright/test": "^1.28.0"
+ }
+}
diff --git a/crates/website/end2end/playwright.config.ts b/crates/website/end2end/playwright.config.ts
new file mode 100644
index 00000000..e9891c09
--- /dev/null
+++ b/crates/website/end2end/playwright.config.ts
@@ -0,0 +1,107 @@
+import type { PlaywrightTestConfig } from "@playwright/test";
+import { devices } from "@playwright/test";
+
+/**
+ * Read environment variables from file.
+ * https://github.com/motdotla/dotenv
+ */
+// require('dotenv').config();
+
+/**
+ * See https://playwright.dev/docs/test-configuration.
+ */
+const config: PlaywrightTestConfig = {
+ testDir: "./tests",
+ /* Maximum time one test can run for. */
+ timeout: 30 * 1000,
+ expect: {
+ /**
+ * Maximum time expect() should wait for the condition to be met.
+ * For example in `await expect(locator).toHaveText();`
+ */
+ timeout: 5000,
+ },
+ /* Run tests in files in parallel */
+ fullyParallel: true,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 0,
+ /* Opt out of parallel tests on CI. */
+ workers: process.env.CI ? 1 : undefined,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: "html",
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
+ actionTimeout: 0,
+ /* Base URL to use in actions like `await page.goto('/')`. */
+ // baseURL: 'http://localhost:3000',
+
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: "on-first-retry",
+ },
+
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: "chromium",
+ use: {
+ ...devices["Desktop Chrome"],
+ },
+ },
+
+ {
+ name: "firefox",
+ use: {
+ ...devices["Desktop Firefox"],
+ },
+ },
+
+ {
+ name: "webkit",
+ use: {
+ ...devices["Desktop Safari"],
+ },
+ },
+
+ /* Test against mobile viewports. */
+ // {
+ // name: 'Mobile Chrome',
+ // use: {
+ // ...devices['Pixel 5'],
+ // },
+ // },
+ // {
+ // name: 'Mobile Safari',
+ // use: {
+ // ...devices['iPhone 12'],
+ // },
+ // },
+
+ /* Test against branded browsers. */
+ // {
+ // name: 'Microsoft Edge',
+ // use: {
+ // channel: 'msedge',
+ // },
+ // },
+ // {
+ // name: 'Google Chrome',
+ // use: {
+ // channel: 'chrome',
+ // },
+ // },
+ ],
+
+ /* Folder for test artifacts such as screenshots, videos, traces, etc. */
+ // outputDir: 'test-results/',
+
+ /* Run your local dev server before starting the tests */
+ // webServer: {
+ // command: 'npm run start',
+ // port: 3000,
+ // },
+};
+
+export default config;
diff --git a/crates/website/end2end/tests/example.spec.ts b/crates/website/end2end/tests/example.spec.ts
new file mode 100644
index 00000000..a461f351
--- /dev/null
+++ b/crates/website/end2end/tests/example.spec.ts
@@ -0,0 +1,9 @@
+import { test, expect } from "@playwright/test";
+
+test("homepage has title and links to intro page", async ({ page }) => {
+ await page.goto("http://localhost:3000/");
+
+ await expect(page).toHaveTitle("Welcome to Leptos");
+
+ await expect(page.locator("h1")).toHaveText("Welcome to Leptos!");
+});
diff --git a/crates/website/src/app.rs b/crates/website/src/app.rs
new file mode 100644
index 00000000..bb232ea1
--- /dev/null
+++ b/crates/website/src/app.rs
@@ -0,0 +1,63 @@
+use leptos::*;
+use leptos_meta::*;
+use leptos_router::*;
+
+#[component]
+pub fn App(cx: Scope) -> impl IntoView {
+ // Provides context that manages stylesheets, titles, meta tags, etc.
+ provide_meta_context(cx);
+
+ view! { cx,
+ // injects a stylesheet into the document
+ // id=leptos means cargo-leptos will hot-reload this stylesheet
+
+
+ // sets the document title
+
+
+ // content for this welcome page
+
+
+
+
+
+
+
+
+ }
+}
+
+/// Renders the home page of your application.
+#[component]
+fn HomePage(cx: Scope) -> impl IntoView {
+ // Creates a reactive value to update the button
+ let (count, set_count) = create_signal(cx, 0);
+ let on_click = move |_| set_count.update(|count| *count += 1);
+
+ view! { cx,
+ "Welcome to Leptos!"
+ "Click Me: " {count}
+ }
+}
+
+/// 404 - Not Found
+#[component]
+fn NotFound(cx: Scope) -> impl IntoView {
+ // set an HTTP status code 404
+ // this is feature gated because it can only be done during
+ // initial server-side rendering
+ // if you navigate to the 404 page subsequently, the status
+ // code will not be set because there is not a new HTTP request
+ // to the server
+ #[cfg(feature = "ssr")]
+ {
+ // this can be done inline because it's synchronous
+ // if it were async, we'd use a server function
+ let resp = expect_context::(cx);
+ resp.set_status(actix_web::http::StatusCode::NOT_FOUND);
+ }
+
+ view! { cx,
+ "Not Found"
+ }
+}
diff --git a/crates/website/src/lib.rs b/crates/website/src/lib.rs
new file mode 100644
index 00000000..823ab582
--- /dev/null
+++ b/crates/website/src/lib.rs
@@ -0,0 +1,21 @@
+pub mod app;
+use cfg_if::cfg_if;
+
+cfg_if! {
+if #[cfg(feature = "hydrate")] {
+
+ use wasm_bindgen::prelude::wasm_bindgen;
+
+ #[wasm_bindgen]
+ pub fn hydrate() {
+ use app::*;
+ use leptos::*;
+
+ console_error_panic_hook::set_once();
+
+ leptos::mount_to_body(move |cx| {
+ view! { cx, }
+ });
+ }
+}
+}
diff --git a/crates/website/src/main.rs b/crates/website/src/main.rs
new file mode 100644
index 00000000..bbcff6f0
--- /dev/null
+++ b/crates/website/src/main.rs
@@ -0,0 +1,76 @@
+#[cfg(feature = "ssr")]
+#[actix_web::main]
+async fn main() -> std::io::Result<()> {
+ use actix_files::Files;
+ use actix_web::*;
+ use leptos::*;
+ use leptos_actix::{generate_route_list, LeptosRoutes};
+ use website::app::*;
+
+ let conf = get_configuration(None).await.unwrap();
+ let addr = conf.leptos_options.site_addr;
+ // Generate the list of routes in your Leptos App
+ let routes = generate_route_list(|cx| view! { cx, });
+
+ HttpServer::new(move || {
+ let leptos_options = &conf.leptos_options;
+ let site_root = &leptos_options.site_root;
+
+ App::new()
+ .route("/api/{tail:.*}", leptos_actix::handle_server_fns())
+ // serve JS/WASM/CSS from `pkg`
+ .service(Files::new("/pkg", format!("{site_root}/pkg")))
+ // serve other assets from the `assets` directory
+ .service(Files::new("/assets", site_root))
+ // serve the favicon from /favicon.ico
+ .service(favicon)
+ .leptos_routes(
+ leptos_options.to_owned(),
+ routes.to_owned(),
+ |cx| view! { cx, },
+ )
+ .app_data(web::Data::new(leptos_options.to_owned()))
+ //.wrap(middleware::Compress::default())
+ })
+ .bind(&addr)?
+ .run()
+ .await
+}
+
+#[cfg(feature = "ssr")]
+#[actix_web::get("favicon.ico")]
+async fn favicon(
+ leptos_options: actix_web::web::Data,
+) -> actix_web::Result {
+ let leptos_options = leptos_options.into_inner();
+ let site_root = &leptos_options.site_root;
+ Ok(actix_files::NamedFile::open(format!(
+ "{site_root}/favicon.ico"
+ ))?)
+}
+
+#[cfg(not(any(feature = "ssr", feature = "csr")))]
+pub fn main() {
+ // no client-side main function
+ // unless we want this to work with e.g., Trunk for pure client-side testing
+ // see lib.rs for hydration function instead
+ // see optional feature `csr` instead
+}
+
+#[cfg(all(not(feature = "ssr"), feature = "csr"))]
+pub fn main() {
+ // a client-side main function is required for using `trunk serve`
+ // prefer using `cargo leptos serve` instead
+ // to run: `trunk serve --open --features csr`
+ use leptos::*;
+ use website::app::*;
+ use wasm_bindgen::prelude::wasm_bindgen;
+
+ console_error_panic_hook::set_once();
+
+ leptos::mount_to_body(move |cx| {
+ // note: for testing it may be preferrable to replace this with a
+ // more specific component, although leptos_router should still work
+ view! {cx, }
+ });
+}
diff --git a/crates/website/style/main.scss b/crates/website/style/main.scss
new file mode 100644
index 00000000..e4538e15
--- /dev/null
+++ b/crates/website/style/main.scss
@@ -0,0 +1,4 @@
+body {
+ font-family: sans-serif;
+ text-align: center;
+}
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 6591c339..69bad4da 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -27,6 +27,15 @@ services:
ports:
- "8080:8080"
+ website:
+ image: ${IMAGE_WEBSITE}
+ restart: always
+ env_file: .env
+ build:
+ dockerfile: services/website/Dockerfile
+ ports:
+ - "8000:8000"
+
bot:
image: ${IMAGE_BOT}
restart: always
diff --git a/services/bot1/Dockerfile b/services/bot1/Dockerfile
new file mode 100644
index 00000000..c7ecfcb2
--- /dev/null
+++ b/services/bot1/Dockerfile
@@ -0,0 +1,53 @@
+FROM rust:1.70.0-slim-buster as builder
+WORKDIR /usr/src/starboard
+
+# nightly
+RUN rustup default nightly
+
+# force cargo to update the crates.io index.
+RUN cargo search --limit 0
+
+# install pkg-config (required for reqwest dependency)
+RUN apt-get update
+RUN apt-get install -y pkg-config libssl-dev
+
+# cache dependencies
+COPY Cargo.lock Cargo.lock
+COPY Cargo.toml Cargo.toml
+
+COPY crates/common/Cargo.toml crates/common/Cargo.toml
+COPY crates/database/Cargo.toml crates/database/Cargo.toml
+COPY crates/errors/Cargo.toml crates/errors/Cargo.toml
+COPY crates/website/Cargo.toml crates/website/Cargo.toml
+COPY crates/starboard/Cargo.toml crates/starboard/Cargo.toml
+
+RUN mkdir crates/common/src && touch crates/common/src/lib.rs
+RUN mkdir crates/database/src && touch crates/database/src/lib.rs
+RUN mkdir crates/errors/src && touch crates/errors/src/lib.rs
+RUN mkdir crates/website/src && touch crates/website/src/lib.rs
+RUN mkdir crates/starboard/src && echo "fn main() { dbg!(1); }" > crates/starboard/src/main.rs
+
+RUN cargo build --bin starboard --release
+RUN rm target/release/starboard
+RUN rm -r crates
+
+# copy what we need
+COPY crates crates
+COPY sqlx-data.json sqlx-data.json
+
+# install starboard
+RUN cargo install cargo-edit
+RUN cargo set-version --workspace --bump major
+RUN cargo build --bin starboard --release
+
+# get rid of cargo
+FROM debian:buster-slim
+
+# install certificates
+RUN apt-get update && apt-get install -y ca-certificates
+
+# copy starboard over from the builder
+COPY --from=builder /usr/src/starboard/target/release/starboard /usr/local/bin/starboard
+
+# run starboard
+CMD ["starboard"]
diff --git a/services/website/Dockerfile b/services/website/Dockerfile
new file mode 100644
index 00000000..83bc08b3
--- /dev/null
+++ b/services/website/Dockerfile
@@ -0,0 +1,66 @@
+FROM rust:1.71.0-slim-bullseye as prereq
+
+RUN rustup default nightly
+RUN rustup target add wasm32-unknown-unknown
+
+RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
+RUN apt-get update
+RUN apt-get install -y pkg-config libssl-dev nodejs npm
+RUN npm install -g sass
+
+RUN cargo install cargo-chef
+RUN cargo install cargo-leptos
+
+FROM prereq AS planner
+WORKDIR /app
+
+COPY crates crates
+COPY sqlx-data.json sqlx-data.json
+COPY Cargo.toml Cargo.toml
+COPY Cargo.lock Cargo.lock
+
+RUN cargo chef prepare --recipe-path recipe.json
+
+FROM prereq as cacher
+WORKDIR /app
+COPY --from=planner /app/recipe.json recipe.json
+RUN cargo chef cook --release --package=website --bin=website --target-dir=target/server --no-default-features --features=ssr --recipe-path recipe.json
+RUN cargo chef cook --release --package=website --target-dir=target/front --target=wasm32-unknown-unknown --no-default-features --features=hydrate --recipe-path recipe.json
+
+FROM prereq as builder
+WORKDIR /app
+
+COPY crates crates
+COPY sqlx-data.json sqlx-data.json
+COPY Cargo.toml Cargo.toml
+COPY Cargo.lock Cargo.lock
+
+# copy dependecies
+COPY --from=cacher /app/target /app/target
+COPY --from=cacher /usr/local/cargo /usr/local/cargo
+# set env variables for build
+# The source style file. If it ends with _.sass_ or _.scss_ then it will be compiled by `dart-sass`
+# into CSS and processed by lightning css. When release is set, then it will also be minified.
+ENV LEPTOS_STYLE_FILE "style/main.scss"
+# The browserlist https://browsersl.ist query used for optimizing the CSS.
+ENV LEPTOS_BROWSERQUERY "defaults"
+# build the app
+RUN cargo leptos build --release
+
+# use googles distroless as runtime image
+FROM gcr.io/distroless/cc-debian11
+# copy app form builder
+COPY --from=builder /app/target/server/release/website /app/
+COPY --from=builder /app/target/site /app/site
+WORKDIR /app
+
+# Site .env parameters cargo-leptos
+ENV OUTPUT_NAME "website"
+ENV LEPTOS_OUTPUT_NAME "website"
+ENV LEPTOS_SITE_ROOT "site"
+ENV LEPTOS_SITE_PKG_DIR "pkg"
+ENV LEPTOS_ASSETS_DIR "assets"
+ENV LEPTOS_SITE_ADDR "0.0.0.0:8000"
+
+# start the application
+CMD ["./website"]
From 862da009de2ba3930eeb386847c7b63650e94453 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 13:08:57 -0400
Subject: [PATCH 002/119] daisyui
---
crates/website/Cargo.toml | 2 +-
crates/website/input.css | 3 +
crates/website/src/app.rs | 4 +-
crates/website/src/main.rs | 2 +-
crates/website/style/main.scss | 4 -
crates/website/style/output.css | 1011 +++++++++++++++++++++++++++++
crates/website/tailwind.config.js | 10 +
services/website/Dockerfile | 2 +-
8 files changed, 1029 insertions(+), 9 deletions(-)
create mode 100644 crates/website/input.css
delete mode 100644 crates/website/style/main.scss
create mode 100644 crates/website/style/output.css
create mode 100644 crates/website/tailwind.config.js
diff --git a/crates/website/Cargo.toml b/crates/website/Cargo.toml
index f6bda04e..570f70bf 100644
--- a/crates/website/Cargo.toml
+++ b/crates/website/Cargo.toml
@@ -39,7 +39,7 @@ site-root = "target/site"
# Defaults to pkg
site-pkg-dir = "pkg"
# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to //app.css
-style-file = "style/main.scss"
+style-file = "style/output.css"
# Assets source dir. All files found here will be copied and synchronized to site-root.
# The assets-dir cannot have a sub directory with the same name/path as site-pkg-dir.
#
diff --git a/crates/website/input.css b/crates/website/input.css
new file mode 100644
index 00000000..b5c61c95
--- /dev/null
+++ b/crates/website/input.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/crates/website/src/app.rs b/crates/website/src/app.rs
index bb232ea1..a09011d8 100644
--- a/crates/website/src/app.rs
+++ b/crates/website/src/app.rs
@@ -10,7 +10,7 @@ pub fn App(cx: Scope) -> impl IntoView {
view! { cx,
// injects a stylesheet into the document
// id=leptos means cargo-leptos will hot-reload this stylesheet
-
+
// sets the document title
@@ -36,7 +36,7 @@ fn HomePage(cx: Scope) -> impl IntoView {
view! { cx,
"Welcome to Leptos!"
- "Click Me: " {count}
+ "Click Me: " {count}
}
}
diff --git a/crates/website/src/main.rs b/crates/website/src/main.rs
index bbcff6f0..d5d15e8f 100644
--- a/crates/website/src/main.rs
+++ b/crates/website/src/main.rs
@@ -63,8 +63,8 @@ pub fn main() {
// prefer using `cargo leptos serve` instead
// to run: `trunk serve --open --features csr`
use leptos::*;
- use website::app::*;
use wasm_bindgen::prelude::wasm_bindgen;
+ use website::app::*;
console_error_panic_hook::set_once();
diff --git a/crates/website/style/main.scss b/crates/website/style/main.scss
deleted file mode 100644
index e4538e15..00000000
--- a/crates/website/style/main.scss
+++ /dev/null
@@ -1,4 +0,0 @@
-body {
- font-family: sans-serif;
- text-align: center;
-}
\ No newline at end of file
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
new file mode 100644
index 00000000..a5e8e5c3
--- /dev/null
+++ b/crates/website/style/output.css
@@ -0,0 +1,1011 @@
+/*
+! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com
+*/
+
+/*
+1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
+2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
+*/
+
+*,
+::before,
+::after {
+ box-sizing: border-box;
+ /* 1 */
+ border-width: 0;
+ /* 2 */
+ border-style: solid;
+ /* 2 */
+ border-color: #e5e7eb;
+ /* 2 */
+}
+
+::before,
+::after {
+ --tw-content: '';
+}
+
+/*
+1. Use a consistent sensible line-height in all browsers.
+2. Prevent adjustments of font size after orientation changes in iOS.
+3. Use a more readable tab size.
+4. Use the user's configured `sans` font-family by default.
+5. Use the user's configured `sans` font-feature-settings by default.
+6. Use the user's configured `sans` font-variation-settings by default.
+*/
+
+html {
+ line-height: 1.5;
+ /* 1 */
+ -webkit-text-size-adjust: 100%;
+ /* 2 */
+ -moz-tab-size: 4;
+ /* 3 */
+ -o-tab-size: 4;
+ tab-size: 4;
+ /* 3 */
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ /* 4 */
+ font-feature-settings: normal;
+ /* 5 */
+ font-variation-settings: normal;
+ /* 6 */
+}
+
+/*
+1. Remove the margin in all browsers.
+2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
+*/
+
+body {
+ margin: 0;
+ /* 1 */
+ line-height: inherit;
+ /* 2 */
+}
+
+/*
+1. Add the correct height in Firefox.
+2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
+3. Ensure horizontal rules are visible by default.
+*/
+
+hr {
+ height: 0;
+ /* 1 */
+ color: inherit;
+ /* 2 */
+ border-top-width: 1px;
+ /* 3 */
+}
+
+/*
+Add the correct text decoration in Chrome, Edge, and Safari.
+*/
+
+abbr:where([title]) {
+ -webkit-text-decoration: underline dotted;
+ text-decoration: underline dotted;
+}
+
+/*
+Remove the default font size and weight for headings.
+*/
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-size: inherit;
+ font-weight: inherit;
+}
+
+/*
+Reset links to optimize for opt-in styling instead of opt-out.
+*/
+
+a {
+ color: inherit;
+ text-decoration: inherit;
+}
+
+/*
+Add the correct font weight in Edge and Safari.
+*/
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+/*
+1. Use the user's configured `mono` font family by default.
+2. Correct the odd `em` font sizing in all browsers.
+*/
+
+code,
+kbd,
+samp,
+pre {
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ /* 1 */
+ font-size: 1em;
+ /* 2 */
+}
+
+/*
+Add the correct font size in all browsers.
+*/
+
+small {
+ font-size: 80%;
+}
+
+/*
+Prevent `sub` and `sup` elements from affecting the line height in all browsers.
+*/
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/*
+1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
+2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
+3. Remove gaps between table borders by default.
+*/
+
+table {
+ text-indent: 0;
+ /* 1 */
+ border-color: inherit;
+ /* 2 */
+ border-collapse: collapse;
+ /* 3 */
+}
+
+/*
+1. Change the font styles in all browsers.
+2. Remove the margin in Firefox and Safari.
+3. Remove default padding in all browsers.
+*/
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit;
+ /* 1 */
+ font-feature-settings: inherit;
+ /* 1 */
+ font-variation-settings: inherit;
+ /* 1 */
+ font-size: 100%;
+ /* 1 */
+ font-weight: inherit;
+ /* 1 */
+ line-height: inherit;
+ /* 1 */
+ color: inherit;
+ /* 1 */
+ margin: 0;
+ /* 2 */
+ padding: 0;
+ /* 3 */
+}
+
+/*
+Remove the inheritance of text transform in Edge and Firefox.
+*/
+
+button,
+select {
+ text-transform: none;
+}
+
+/*
+1. Correct the inability to style clickable types in iOS and Safari.
+2. Remove default button styles.
+*/
+
+button,
+[type='button'],
+[type='reset'],
+[type='submit'] {
+ -webkit-appearance: button;
+ /* 1 */
+ background-color: transparent;
+ /* 2 */
+ background-image: none;
+ /* 2 */
+}
+
+/*
+Use the modern Firefox focus style for all focusable elements.
+*/
+
+:-moz-focusring {
+ outline: auto;
+}
+
+/*
+Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
+*/
+
+:-moz-ui-invalid {
+ box-shadow: none;
+}
+
+/*
+Add the correct vertical alignment in Chrome and Firefox.
+*/
+
+progress {
+ vertical-align: baseline;
+}
+
+/*
+Correct the cursor style of increment and decrement buttons in Safari.
+*/
+
+::-webkit-inner-spin-button,
+::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/*
+1. Correct the odd appearance in Chrome and Safari.
+2. Correct the outline style in Safari.
+*/
+
+[type='search'] {
+ -webkit-appearance: textfield;
+ /* 1 */
+ outline-offset: -2px;
+ /* 2 */
+}
+
+/*
+Remove the inner padding in Chrome and Safari on macOS.
+*/
+
+::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/*
+1. Correct the inability to style clickable types in iOS and Safari.
+2. Change font properties to `inherit` in Safari.
+*/
+
+::-webkit-file-upload-button {
+ -webkit-appearance: button;
+ /* 1 */
+ font: inherit;
+ /* 2 */
+}
+
+/*
+Add the correct display in Chrome and Safari.
+*/
+
+summary {
+ display: list-item;
+}
+
+/*
+Removes the default spacing and border for appropriate elements.
+*/
+
+blockquote,
+dl,
+dd,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+hr,
+figure,
+p,
+pre {
+ margin: 0;
+}
+
+fieldset {
+ margin: 0;
+ padding: 0;
+}
+
+legend {
+ padding: 0;
+}
+
+ol,
+ul,
+menu {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+/*
+Reset default styling for dialogs.
+*/
+
+dialog {
+ padding: 0;
+}
+
+/*
+Prevent resizing textareas horizontally by default.
+*/
+
+textarea {
+ resize: vertical;
+}
+
+/*
+1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
+2. Set the default placeholder color to the user's configured gray 400 color.
+*/
+
+input::-moz-placeholder, textarea::-moz-placeholder {
+ opacity: 1;
+ /* 1 */
+ color: #9ca3af;
+ /* 2 */
+}
+
+input::placeholder,
+textarea::placeholder {
+ opacity: 1;
+ /* 1 */
+ color: #9ca3af;
+ /* 2 */
+}
+
+/*
+Set the default cursor for buttons.
+*/
+
+button,
+[role="button"] {
+ cursor: pointer;
+}
+
+/*
+Make sure disabled buttons don't get the pointer cursor.
+*/
+
+:disabled {
+ cursor: default;
+}
+
+/*
+1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
+2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
+ This can trigger a poorly considered lint error in some tools but is included by design.
+*/
+
+img,
+svg,
+video,
+canvas,
+audio,
+iframe,
+embed,
+object {
+ display: block;
+ /* 1 */
+ vertical-align: middle;
+ /* 2 */
+}
+
+/*
+Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
+*/
+
+img,
+video {
+ max-width: 100%;
+ height: auto;
+}
+
+/* Make elements with the HTML hidden attribute stay hidden by default */
+
+[hidden] {
+ display: none;
+}
+
+:root,
+[data-theme] {
+ background-color: hsl(var(--b1) / var(--tw-bg-opacity, 1));
+ color: hsl(var(--bc) / var(--tw-text-opacity, 1));
+}
+
+html {
+ -webkit-tap-highlight-color: transparent;
+}
+
+:root {
+ color-scheme: light;
+ --pf: 259 94% 44%;
+ --sf: 314 100% 40%;
+ --af: 174 75% 39%;
+ --nf: 214 20% 14%;
+ --in: 198 93% 60%;
+ --su: 158 64% 52%;
+ --wa: 43 96% 56%;
+ --er: 0 91% 71%;
+ --inc: 198 100% 12%;
+ --suc: 158 100% 10%;
+ --wac: 43 100% 11%;
+ --erc: 0 100% 14%;
+ --rounded-box: 1rem;
+ --rounded-btn: 0.5rem;
+ --rounded-badge: 1.9rem;
+ --animation-btn: 0.25s;
+ --animation-input: .2s;
+ --btn-text-case: uppercase;
+ --btn-focus-scale: 0.95;
+ --border-btn: 1px;
+ --tab-border: 1px;
+ --tab-radius: 0.5rem;
+ --p: 259 94% 51%;
+ --pc: 259 96% 91%;
+ --s: 314 100% 47%;
+ --sc: 314 100% 91%;
+ --a: 174 75% 46%;
+ --ac: 174 75% 11%;
+ --n: 214 20% 21%;
+ --nc: 212 19% 87%;
+ --b1: 0 0% 100%;
+ --b2: 0 0% 95%;
+ --b3: 180 2% 90%;
+ --bc: 215 28% 17%;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ color-scheme: dark;
+ --pf: 262 80% 43%;
+ --sf: 316 70% 43%;
+ --af: 175 70% 34%;
+ --in: 198 93% 60%;
+ --su: 158 64% 52%;
+ --wa: 43 96% 56%;
+ --er: 0 91% 71%;
+ --inc: 198 100% 12%;
+ --suc: 158 100% 10%;
+ --wac: 43 100% 11%;
+ --erc: 0 100% 14%;
+ --rounded-box: 1rem;
+ --rounded-btn: 0.5rem;
+ --rounded-badge: 1.9rem;
+ --animation-btn: 0.25s;
+ --animation-input: .2s;
+ --btn-text-case: uppercase;
+ --btn-focus-scale: 0.95;
+ --border-btn: 1px;
+ --tab-border: 1px;
+ --tab-radius: 0.5rem;
+ --p: 262 80% 50%;
+ --pc: 0 0% 100%;
+ --s: 316 70% 50%;
+ --sc: 0 0% 100%;
+ --a: 175 70% 41%;
+ --ac: 0 0% 100%;
+ --n: 213 18% 20%;
+ --nf: 212 17% 17%;
+ --nc: 220 13% 69%;
+ --b1: 212 18% 14%;
+ --b2: 213 18% 12%;
+ --b3: 213 18% 10%;
+ --bc: 220 13% 69%;
+ }
+}
+
+[data-theme=light] {
+ color-scheme: light;
+ --pf: 259 94% 44%;
+ --sf: 314 100% 40%;
+ --af: 174 75% 39%;
+ --nf: 214 20% 14%;
+ --in: 198 93% 60%;
+ --su: 158 64% 52%;
+ --wa: 43 96% 56%;
+ --er: 0 91% 71%;
+ --inc: 198 100% 12%;
+ --suc: 158 100% 10%;
+ --wac: 43 100% 11%;
+ --erc: 0 100% 14%;
+ --rounded-box: 1rem;
+ --rounded-btn: 0.5rem;
+ --rounded-badge: 1.9rem;
+ --animation-btn: 0.25s;
+ --animation-input: .2s;
+ --btn-text-case: uppercase;
+ --btn-focus-scale: 0.95;
+ --border-btn: 1px;
+ --tab-border: 1px;
+ --tab-radius: 0.5rem;
+ --p: 259 94% 51%;
+ --pc: 259 96% 91%;
+ --s: 314 100% 47%;
+ --sc: 314 100% 91%;
+ --a: 174 75% 46%;
+ --ac: 174 75% 11%;
+ --n: 214 20% 21%;
+ --nc: 212 19% 87%;
+ --b1: 0 0% 100%;
+ --b2: 0 0% 95%;
+ --b3: 180 2% 90%;
+ --bc: 215 28% 17%;
+}
+
+[data-theme=dark] {
+ color-scheme: dark;
+ --pf: 262 80% 43%;
+ --sf: 316 70% 43%;
+ --af: 175 70% 34%;
+ --in: 198 93% 60%;
+ --su: 158 64% 52%;
+ --wa: 43 96% 56%;
+ --er: 0 91% 71%;
+ --inc: 198 100% 12%;
+ --suc: 158 100% 10%;
+ --wac: 43 100% 11%;
+ --erc: 0 100% 14%;
+ --rounded-box: 1rem;
+ --rounded-btn: 0.5rem;
+ --rounded-badge: 1.9rem;
+ --animation-btn: 0.25s;
+ --animation-input: .2s;
+ --btn-text-case: uppercase;
+ --btn-focus-scale: 0.95;
+ --border-btn: 1px;
+ --tab-border: 1px;
+ --tab-radius: 0.5rem;
+ --p: 262 80% 50%;
+ --pc: 0 0% 100%;
+ --s: 316 70% 50%;
+ --sc: 0 0% 100%;
+ --a: 175 70% 41%;
+ --ac: 0 0% 100%;
+ --n: 213 18% 20%;
+ --nf: 212 17% 17%;
+ --nc: 220 13% 69%;
+ --b1: 212 18% 14%;
+ --b2: 213 18% 12%;
+ --b3: 213 18% 10%;
+ --bc: 220 13% 69%;
+}
+
+*, ::before, ::after {
+ --tw-border-spacing-x: 0;
+ --tw-border-spacing-y: 0;
+ --tw-translate-x: 0;
+ --tw-translate-y: 0;
+ --tw-rotate: 0;
+ --tw-skew-x: 0;
+ --tw-skew-y: 0;
+ --tw-scale-x: 1;
+ --tw-scale-y: 1;
+ --tw-pan-x: ;
+ --tw-pan-y: ;
+ --tw-pinch-zoom: ;
+ --tw-scroll-snap-strictness: proximity;
+ --tw-gradient-from-position: ;
+ --tw-gradient-via-position: ;
+ --tw-gradient-to-position: ;
+ --tw-ordinal: ;
+ --tw-slashed-zero: ;
+ --tw-numeric-figure: ;
+ --tw-numeric-spacing: ;
+ --tw-numeric-fraction: ;
+ --tw-ring-inset: ;
+ --tw-ring-offset-width: 0px;
+ --tw-ring-offset-color: #fff;
+ --tw-ring-color: rgb(59 130 246 / 0.5);
+ --tw-ring-offset-shadow: 0 0 #0000;
+ --tw-ring-shadow: 0 0 #0000;
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-colored: 0 0 #0000;
+ --tw-blur: ;
+ --tw-brightness: ;
+ --tw-contrast: ;
+ --tw-grayscale: ;
+ --tw-hue-rotate: ;
+ --tw-invert: ;
+ --tw-saturate: ;
+ --tw-sepia: ;
+ --tw-drop-shadow: ;
+ --tw-backdrop-blur: ;
+ --tw-backdrop-brightness: ;
+ --tw-backdrop-contrast: ;
+ --tw-backdrop-grayscale: ;
+ --tw-backdrop-hue-rotate: ;
+ --tw-backdrop-invert: ;
+ --tw-backdrop-opacity: ;
+ --tw-backdrop-saturate: ;
+ --tw-backdrop-sepia: ;
+}
+
+::backdrop {
+ --tw-border-spacing-x: 0;
+ --tw-border-spacing-y: 0;
+ --tw-translate-x: 0;
+ --tw-translate-y: 0;
+ --tw-rotate: 0;
+ --tw-skew-x: 0;
+ --tw-skew-y: 0;
+ --tw-scale-x: 1;
+ --tw-scale-y: 1;
+ --tw-pan-x: ;
+ --tw-pan-y: ;
+ --tw-pinch-zoom: ;
+ --tw-scroll-snap-strictness: proximity;
+ --tw-gradient-from-position: ;
+ --tw-gradient-via-position: ;
+ --tw-gradient-to-position: ;
+ --tw-ordinal: ;
+ --tw-slashed-zero: ;
+ --tw-numeric-figure: ;
+ --tw-numeric-spacing: ;
+ --tw-numeric-fraction: ;
+ --tw-ring-inset: ;
+ --tw-ring-offset-width: 0px;
+ --tw-ring-offset-color: #fff;
+ --tw-ring-color: rgb(59 130 246 / 0.5);
+ --tw-ring-offset-shadow: 0 0 #0000;
+ --tw-ring-shadow: 0 0 #0000;
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-colored: 0 0 #0000;
+ --tw-blur: ;
+ --tw-brightness: ;
+ --tw-contrast: ;
+ --tw-grayscale: ;
+ --tw-hue-rotate: ;
+ --tw-invert: ;
+ --tw-saturate: ;
+ --tw-sepia: ;
+ --tw-drop-shadow: ;
+ --tw-backdrop-blur: ;
+ --tw-backdrop-brightness: ;
+ --tw-backdrop-contrast: ;
+ --tw-backdrop-grayscale: ;
+ --tw-backdrop-hue-rotate: ;
+ --tw-backdrop-invert: ;
+ --tw-backdrop-opacity: ;
+ --tw-backdrop-saturate: ;
+ --tw-backdrop-sepia: ;
+}
+
+.btn {
+ display: inline-flex;
+ flex-shrink: 0;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: center;
+ border-color: transparent;
+ border-color: hsl(var(--b2) / var(--tw-border-opacity));
+ text-align: center;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ transition-duration: 200ms;
+ border-radius: var(--rounded-btn, 0.5rem);
+ height: 3rem;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ line-height: 1em;
+ min-height: 3rem;
+ gap: 0.5rem;
+ font-weight: 600;
+ text-decoration-line: none;
+ border-width: var(--border-btn, 1px);
+ animation: button-pop var(--animation-btn, 0.25s) ease-out;
+ text-transform: var(--btn-text-case, uppercase);
+ --tw-border-opacity: 1;
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b2) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ outline-color: hsl(var(--bc) / 1);
+}
+
+.btn-disabled,
+ .btn[disabled],
+ .btn:disabled {
+ pointer-events: none;
+}
+
+.btn-group > input[type="radio"].btn {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+}
+
+.btn-group > input[type="radio"].btn:before {
+ content: attr(data-title);
+}
+
+.btn:is(input[type="checkbox"]),
+.btn:is(input[type="radio"]) {
+ width: auto;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+}
+
+.btn:is(input[type="checkbox"]):after,
+.btn:is(input[type="radio"]):after {
+ --tw-content: attr(aria-label);
+ content: var(--tw-content);
+}
+
+@media (hover: hover) {
+ .btn:hover {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--b3) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b3) / var(--tw-bg-opacity));
+ }
+
+ .btn.glass:hover {
+ --glass-opacity: 25%;
+ --glass-border-opacity: 15%;
+ }
+
+ .btn-disabled:hover,
+ .btn[disabled]:hover,
+ .btn:disabled:hover {
+ --tw-border-opacity: 0;
+ background-color: hsl(var(--n) / var(--tw-bg-opacity));
+ --tw-bg-opacity: 0.2;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ --tw-text-opacity: 0.2;
+ }
+
+ .btn:is(input[type="checkbox"]:checked):hover, .btn:is(input[type="radio"]:checked):hover {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--pf) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--pf) / var(--tw-bg-opacity));
+ }
+}
+
+.btn:active:hover,
+ .btn:active:focus {
+ animation: button-pop 0s ease-out;
+ transform: scale(var(--btn-focus-scale, 0.97));
+}
+
+.btn:focus-visible {
+ outline-style: solid;
+ outline-width: 2px;
+ outline-offset: 2px;
+}
+
+.btn.glass {
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-colored: 0 0 #0000;
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
+ outline-color: currentColor;
+}
+
+.btn.glass.btn-active {
+ --glass-opacity: 25%;
+ --glass-border-opacity: 15%;
+}
+
+.btn.btn-disabled,
+ .btn[disabled],
+ .btn:disabled {
+ --tw-border-opacity: 0;
+ background-color: hsl(var(--n) / var(--tw-bg-opacity));
+ --tw-bg-opacity: 0.2;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ --tw-text-opacity: 0.2;
+}
+
+.btn-group > input[type="radio"]:checked.btn,
+ .btn-group > .btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--p) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--p) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--pc) / var(--tw-text-opacity));
+}
+
+.btn-group > input[type="radio"]:checked.btn:focus-visible, .btn-group > .btn-active:focus-visible {
+ outline-style: solid;
+ outline-width: 2px;
+ outline-color: hsl(var(--p) / 1);
+}
+
+.btn:is(input[type="checkbox"]:checked),
+.btn:is(input[type="radio"]:checked) {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--p) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--p) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--pc) / var(--tw-text-opacity));
+}
+
+.btn:is(input[type="checkbox"]:checked):focus-visible, .btn:is(input[type="radio"]:checked):focus-visible {
+ outline-color: hsl(var(--p) / 1);
+}
+
+@keyframes button-pop {
+ 0% {
+ transform: scale(var(--btn-focus-scale, 0.98));
+ }
+
+ 40% {
+ transform: scale(1.02);
+ }
+
+ 100% {
+ transform: scale(1);
+ }
+}
+
+@keyframes checkmark {
+ 0% {
+ background-position-y: 5px;
+ }
+
+ 50% {
+ background-position-y: -2px;
+ }
+
+ 100% {
+ background-position-y: 0;
+ }
+}
+
+@keyframes modal-pop {
+ 0% {
+ opacity: 0;
+ }
+}
+
+@keyframes progress-loading {
+ 50% {
+ background-position-x: -115%;
+ }
+}
+
+@keyframes radiomark {
+ 0% {
+ box-shadow: 0 0 0 12px hsl(var(--b1)) inset, 0 0 0 12px hsl(var(--b1)) inset;
+ }
+
+ 50% {
+ box-shadow: 0 0 0 3px hsl(var(--b1)) inset, 0 0 0 3px hsl(var(--b1)) inset;
+ }
+
+ 100% {
+ box-shadow: 0 0 0 4px hsl(var(--b1)) inset, 0 0 0 4px hsl(var(--b1)) inset;
+ }
+}
+
+@keyframes rating-pop {
+ 0% {
+ transform: translateY(-0.125em);
+ }
+
+ 40% {
+ transform: translateY(-0.125em);
+ }
+
+ 100% {
+ transform: translateY(0);
+ }
+}
+
+@keyframes toast-pop {
+ 0% {
+ transform: scale(0.9);
+ opacity: 0;
+ }
+
+ 100% {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+.btn-group .btn:not(:first-child):not(:last-child) {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.btn-group .btn:first-child:not(:last-child) {
+ margin-top: -0px;
+ margin-left: -1px;
+ border-top-left-radius: var(--rounded-btn, 0.5rem);
+ border-top-right-radius: 0;
+ border-bottom-left-radius: var(--rounded-btn, 0.5rem);
+ border-bottom-right-radius: 0;
+}
+
+.btn-group .btn:last-child:not(:first-child) {
+ border-top-left-radius: 0;
+ border-top-right-radius: var(--rounded-btn, 0.5rem);
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: var(--rounded-btn, 0.5rem);
+}
+
+.btn-group-horizontal .btn:not(:first-child):not(:last-child) {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.btn-group-horizontal .btn:first-child:not(:last-child) {
+ margin-top: -0px;
+ margin-left: -1px;
+ border-top-left-radius: var(--rounded-btn, 0.5rem);
+ border-top-right-radius: 0;
+ border-bottom-left-radius: var(--rounded-btn, 0.5rem);
+ border-bottom-right-radius: 0;
+}
+
+.btn-group-horizontal .btn:last-child:not(:first-child) {
+ border-top-left-radius: 0;
+ border-top-right-radius: var(--rounded-btn, 0.5rem);
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: var(--rounded-btn, 0.5rem);
+}
+
+.btn-group-vertical .btn:first-child:not(:last-child) {
+ margin-top: -1px;
+ margin-left: -0px;
+ border-top-left-radius: var(--rounded-btn, 0.5rem);
+ border-top-right-radius: var(--rounded-btn, 0.5rem);
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.btn-group-vertical .btn:last-child:not(:first-child) {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-left-radius: var(--rounded-btn, 0.5rem);
+ border-bottom-right-radius: var(--rounded-btn, 0.5rem);
+}
+
+.inline {
+ display: inline;
+}
diff --git a/crates/website/tailwind.config.js b/crates/website/tailwind.config.js
new file mode 100644
index 00000000..cab7f06a
--- /dev/null
+++ b/crates/website/tailwind.config.js
@@ -0,0 +1,10 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: {
+ files: ["*.html", "./src/**/*.rs"],
+ },
+ theme: {
+ extend: {},
+ },
+ plugins: [require("daisyui")],
+};
diff --git a/services/website/Dockerfile b/services/website/Dockerfile
index 83bc08b3..b5bb40c6 100644
--- a/services/website/Dockerfile
+++ b/services/website/Dockerfile
@@ -41,7 +41,7 @@ COPY --from=cacher /usr/local/cargo /usr/local/cargo
# set env variables for build
# The source style file. If it ends with _.sass_ or _.scss_ then it will be compiled by `dart-sass`
# into CSS and processed by lightning css. When release is set, then it will also be minified.
-ENV LEPTOS_STYLE_FILE "style/main.scss"
+ENV LEPTOS_STYLE_FILE "style/output.css"
# The browserlist https://browsersl.ist query used for optimizing the CSS.
ENV LEPTOS_BROWSERQUERY "defaults"
# build the app
From 03d0536f04fd013b1b38ddefa37778959b65aa5d Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 13:12:29 -0400
Subject: [PATCH 003/119] delete bot1/Dockerfile
---
services/bot1/Dockerfile | 53 ----------------------------------------
1 file changed, 53 deletions(-)
delete mode 100644 services/bot1/Dockerfile
diff --git a/services/bot1/Dockerfile b/services/bot1/Dockerfile
deleted file mode 100644
index c7ecfcb2..00000000
--- a/services/bot1/Dockerfile
+++ /dev/null
@@ -1,53 +0,0 @@
-FROM rust:1.70.0-slim-buster as builder
-WORKDIR /usr/src/starboard
-
-# nightly
-RUN rustup default nightly
-
-# force cargo to update the crates.io index.
-RUN cargo search --limit 0
-
-# install pkg-config (required for reqwest dependency)
-RUN apt-get update
-RUN apt-get install -y pkg-config libssl-dev
-
-# cache dependencies
-COPY Cargo.lock Cargo.lock
-COPY Cargo.toml Cargo.toml
-
-COPY crates/common/Cargo.toml crates/common/Cargo.toml
-COPY crates/database/Cargo.toml crates/database/Cargo.toml
-COPY crates/errors/Cargo.toml crates/errors/Cargo.toml
-COPY crates/website/Cargo.toml crates/website/Cargo.toml
-COPY crates/starboard/Cargo.toml crates/starboard/Cargo.toml
-
-RUN mkdir crates/common/src && touch crates/common/src/lib.rs
-RUN mkdir crates/database/src && touch crates/database/src/lib.rs
-RUN mkdir crates/errors/src && touch crates/errors/src/lib.rs
-RUN mkdir crates/website/src && touch crates/website/src/lib.rs
-RUN mkdir crates/starboard/src && echo "fn main() { dbg!(1); }" > crates/starboard/src/main.rs
-
-RUN cargo build --bin starboard --release
-RUN rm target/release/starboard
-RUN rm -r crates
-
-# copy what we need
-COPY crates crates
-COPY sqlx-data.json sqlx-data.json
-
-# install starboard
-RUN cargo install cargo-edit
-RUN cargo set-version --workspace --bump major
-RUN cargo build --bin starboard --release
-
-# get rid of cargo
-FROM debian:buster-slim
-
-# install certificates
-RUN apt-get update && apt-get install -y ca-certificates
-
-# copy starboard over from the builder
-COPY --from=builder /usr/src/starboard/target/release/starboard /usr/local/bin/starboard
-
-# run starboard
-CMD ["starboard"]
From b4f34ec8b5a1d762a549b252cebd3b0949dd8a96 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 13:49:46 -0400
Subject: [PATCH 004/119] Update lib.rs
---
crates/website/src/lib.rs | 26 +++++++++++---------------
1 file changed, 11 insertions(+), 15 deletions(-)
diff --git a/crates/website/src/lib.rs b/crates/website/src/lib.rs
index 823ab582..b3dba96d 100644
--- a/crates/website/src/lib.rs
+++ b/crates/website/src/lib.rs
@@ -1,21 +1,17 @@
pub mod app;
-use cfg_if::cfg_if;
-cfg_if! {
-if #[cfg(feature = "hydrate")] {
+#[cfg(feature = "hydrate")]
+use wasm_bindgen::prelude::wasm_bindgen;
- use wasm_bindgen::prelude::wasm_bindgen;
+#[cfg(feature = "hydrate")]
+#[wasm_bindgen]
+pub fn hydrate() {
+ use app::*;
+ use leptos::*;
- #[wasm_bindgen]
- pub fn hydrate() {
- use app::*;
- use leptos::*;
+ console_error_panic_hook::set_once();
- console_error_panic_hook::set_once();
-
- leptos::mount_to_body(move |cx| {
- view! { cx, }
- });
- }
-}
+ leptos::mount_to_body(move |cx| {
+ view! { cx, }
+ });
}
From 73edfc67d1ca12a2dd39ee3bd88b9c002275a94c Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 13:51:10 -0400
Subject: [PATCH 005/119] push .vscode/settings.json
---
.gitignore | 1 -
.vscode/settings.json | 22 ++++++++++++++++++++++
2 files changed, 22 insertions(+), 1 deletion(-)
create mode 100644 .vscode/settings.json
diff --git a/.gitignore b/.gitignore
index 5608610a..bbdbb5b6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
.env
-.vscode
# Generated by Cargo
# will have compiled files and executables
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..726a3c81
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,22 @@
+{
+ "emmet.includeLanguages": {
+ "rust": "html",
+ "*.rs": "html"
+ },
+ "tailwindCSS.includeLanguages": {
+ "rust": "html",
+ "*.rs": "html"
+ },
+ "files.associations": {
+ "*.rs": "rust"
+ },
+ "editor.quickSuggestions": {
+ "other": "on",
+ "comments": "on",
+ "strings": true
+ },
+ "css.validate": false,
+ "rust-analyzer.procMacro.ignored": {
+ "leptos_macro": ["server", "component"]
+ }
+}
From d320161e9b0a8d8578fbe8e7272e7163e486f07b Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 13:56:30 -0400
Subject: [PATCH 006/119] update .vscode stuff
---
.vscode/extensions.json | 14 ++++++++++++++
.vscode/settings.json | 3 ++-
2 files changed, 16 insertions(+), 1 deletion(-)
create mode 100644 .vscode/extensions.json
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 00000000..d7f09c66
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,14 @@
+{
+ // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
+ // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
+
+ // List of extensions which should be recommended for users of this workspace.
+ "recommendations": [
+ "rust-lang.rust-analyzer",
+ "bradlc.vscode-tailwindcss"
+ ],
+ // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
+ "unwantedRecommendations": [
+
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 726a3c81..52538c5b 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -18,5 +18,6 @@
"css.validate": false,
"rust-analyzer.procMacro.ignored": {
"leptos_macro": ["server", "component"]
- }
+ },
+ "rust-analyzer.check.command": "clippy"
}
From d1da0aa128a24d7738cb29f03ae3cf6b8cd7c81d Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 14:02:23 -0400
Subject: [PATCH 007/119] Update extensions.json
---
.vscode/extensions.json | 16 +++-------------
1 file changed, 3 insertions(+), 13 deletions(-)
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index d7f09c66..03374a2a 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,14 +1,4 @@
{
- // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
- // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
-
- // List of extensions which should be recommended for users of this workspace.
- "recommendations": [
- "rust-lang.rust-analyzer",
- "bradlc.vscode-tailwindcss"
- ],
- // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
- "unwantedRecommendations": [
-
- ]
-}
\ No newline at end of file
+ "recommendations": ["rust-lang.rust-analyzer", "bradlc.vscode-tailwindcss"],
+ "unwantedRecommendations": []
+}
From cb9190563b0c7af37a4fabebb2b38df6c45b8907 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 16:07:50 -0400
Subject: [PATCH 008/119] leptosfmt
---
crates/website/src/app.rs | 9 +++++----
crates/website/src/main.rs | 2 +-
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/crates/website/src/app.rs b/crates/website/src/app.rs
index a09011d8..4dd336bb 100644
--- a/crates/website/src/app.rs
+++ b/crates/website/src/app.rs
@@ -36,7 +36,10 @@ fn HomePage(cx: Scope) -> impl IntoView {
view! { cx,
"Welcome to Leptos!"
- "Click Me: " {count}
+
+ "Click Me: "
+ {count}
+
}
}
@@ -57,7 +60,5 @@ fn NotFound(cx: Scope) -> impl IntoView {
resp.set_status(actix_web::http::StatusCode::NOT_FOUND);
}
- view! { cx,
- "Not Found"
- }
+ view! { cx, "Not Found" }
}
diff --git a/crates/website/src/main.rs b/crates/website/src/main.rs
index d5d15e8f..fcfbafe1 100644
--- a/crates/website/src/main.rs
+++ b/crates/website/src/main.rs
@@ -71,6 +71,6 @@ pub fn main() {
leptos::mount_to_body(move |cx| {
// note: for testing it may be preferrable to replace this with a
// more specific component, although leptos_router should still work
- view! {cx, }
+ view! { cx, }
});
}
From e7e67d78d5708a560fb136da41ee7b2ffe043fea Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 16:50:23 -0400
Subject: [PATCH 009/119] add package(-lock).json to website
---
crates/website/package-lock.json | 941 +++++++++++++++++++++++++++++++
crates/website/package.json | 5 +
2 files changed, 946 insertions(+)
create mode 100644 crates/website/package-lock.json
create mode 100644 crates/website/package.json
diff --git a/crates/website/package-lock.json b/crates/website/package-lock.json
new file mode 100644
index 00000000..2cba883d
--- /dev/null
+++ b/crates/website/package-lock.json
@@ -0,0 +1,941 @@
+{
+ "name": "website",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "daisyui": "^3.5.1"
+ }
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
+ "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
+ "dependencies": {
+ "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.15",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.18",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
+ "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "3.1.0",
+ "@jridgewell/sourcemap-codec": "1.4.14"
+ }
+ },
+ "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.14",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/arg": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/colord": {
+ "version": "2.9.3",
+ "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
+ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw=="
+ },
+ "node_modules/commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+ },
+ "node_modules/css-selector-tokenizer": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
+ "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "fastparse": "^1.1.2"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/daisyui": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.5.1.tgz",
+ "integrity": "sha512-7GG+9QXnr2qQMCqnyFU8TxpaOYJigXiEtmzoivmiiZZHvxqIwYdaMAkgivqTVxEgy3Hot3m1suzZjmt1zUrvmA==",
+ "dependencies": {
+ "colord": "^2.9",
+ "css-selector-tokenizer": "^0.8",
+ "postcss": "^8",
+ "postcss-js": "^4",
+ "tailwindcss": "^3"
+ },
+ "engines": {
+ "node": ">=16.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/daisyui"
+ }
+ },
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
+ },
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
+ "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ=="
+ },
+ "node_modules/fastq": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+ "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "node_modules/glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
+ "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
+ "dependencies": {
+ "has": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/jiti": {
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz",
+ "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==",
+ "bin": {
+ "jiti": "bin/jiti.js"
+ }
+ },
+ "node_modules/lilconfig": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+ "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dependencies": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dependencies": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
+ "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+ },
+ "node_modules/picocolors": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+ "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.4.27",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
+ "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-import": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
+ "node_modules/postcss-js": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
+ "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+ "dependencies": {
+ "camelcase-css": "^2.0.1"
+ },
+ "engines": {
+ "node": "^12 || ^14 || >= 16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.21"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
+ "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
+ "dependencies": {
+ "lilconfig": "^2.0.5",
+ "yaml": "^2.1.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": ">=8.0.9",
+ "ts-node": ">=9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "postcss": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/postcss-nested": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
+ "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
+ "dependencies": {
+ "postcss-selector-parser": "^6.0.11"
+ },
+ "engines": {
+ "node": ">=12.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.2.14"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.0.13",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
+ "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "dependencies": {
+ "pify": "^2.3.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.2",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
+ "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
+ "dependencies": {
+ "is-core-module": "^2.11.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sucrase": {
+ "version": "3.34.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
+ "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "commander": "^4.0.0",
+ "glob": "7.1.6",
+ "lines-and-columns": "^1.1.6",
+ "mz": "^2.7.0",
+ "pirates": "^4.0.1",
+ "ts-interface-checker": "^0.1.9"
+ },
+ "bin": {
+ "sucrase": "bin/sucrase",
+ "sucrase-node": "bin/sucrase-node"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz",
+ "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==",
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "arg": "^5.0.2",
+ "chokidar": "^3.5.3",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.2.12",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "jiti": "^1.18.2",
+ "lilconfig": "^2.1.0",
+ "micromatch": "^4.0.5",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.0.0",
+ "postcss": "^8.4.23",
+ "postcss-import": "^15.1.0",
+ "postcss-js": "^4.0.1",
+ "postcss-load-config": "^4.0.1",
+ "postcss-nested": "^6.0.1",
+ "postcss-selector-parser": "^6.0.11",
+ "resolve": "^1.22.2",
+ "sucrase": "^3.32.0"
+ },
+ "bin": {
+ "tailwind": "lib/cli.js",
+ "tailwindcss": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "dependencies": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "node_modules/thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "dependencies": {
+ "thenify": ">= 3.1.0 < 4"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/ts-interface-checker": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+ },
+ "node_modules/yaml": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz",
+ "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==",
+ "engines": {
+ "node": ">= 14"
+ }
+ }
+ }
+}
diff --git a/crates/website/package.json b/crates/website/package.json
new file mode 100644
index 00000000..fe23ffd9
--- /dev/null
+++ b/crates/website/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "daisyui": "^3.5.1"
+ }
+}
From 609d788b92ef72bd38ab16e8634c7344bf7decaf Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 18:36:54 -0400
Subject: [PATCH 010/119] basic structure
---
.vscode/settings.json | 3 +-
crates/website/src/app.rs | 54 +--
crates/website/src/lib.rs | 1 +
crates/website/src/site/components/mod.rs | 3 +
crates/website/src/site/components/navbar.rs | 33 ++
crates/website/src/site/errors/mod.rs | 1 +
crates/website/src/site/errors/not_found.rs | 20 ++
crates/website/src/site/mod.rs | 3 +
.../website/src/site/routes/dashboard/mod.rs | 8 +
.../src/site/routes/dashboard/server_list.rs | 10 +
crates/website/src/site/routes/mod.rs | 41 +++
.../website/src/site/routes/website/home.rs | 15 +
crates/website/src/site/routes/website/mod.rs | 14 +
crates/website/style/output.css | 326 ++++++++++++++++++
14 files changed, 480 insertions(+), 52 deletions(-)
create mode 100644 crates/website/src/site/components/mod.rs
create mode 100644 crates/website/src/site/components/navbar.rs
create mode 100644 crates/website/src/site/errors/mod.rs
create mode 100644 crates/website/src/site/errors/not_found.rs
create mode 100644 crates/website/src/site/mod.rs
create mode 100644 crates/website/src/site/routes/dashboard/mod.rs
create mode 100644 crates/website/src/site/routes/dashboard/server_list.rs
create mode 100644 crates/website/src/site/routes/mod.rs
create mode 100644 crates/website/src/site/routes/website/home.rs
create mode 100644 crates/website/src/site/routes/website/mod.rs
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 52538c5b..fcfafe58 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -19,5 +19,6 @@
"rust-analyzer.procMacro.ignored": {
"leptos_macro": ["server", "component"]
},
- "rust-analyzer.check.command": "clippy"
+ "rust-analyzer.check.command": "clippy",
+ "rust-analyzer.showUnlinkedFileNotification": false
}
diff --git a/crates/website/src/app.rs b/crates/website/src/app.rs
index 4dd336bb..2620cfe5 100644
--- a/crates/website/src/app.rs
+++ b/crates/website/src/app.rs
@@ -1,64 +1,16 @@
use leptos::*;
use leptos_meta::*;
-use leptos_router::*;
+
+use crate::site::routes::Index;
#[component]
pub fn App(cx: Scope) -> impl IntoView {
- // Provides context that manages stylesheets, titles, meta tags, etc.
provide_meta_context(cx);
view! { cx,
- // injects a stylesheet into the document
- // id=leptos means cargo-leptos will hot-reload this stylesheet
-
- // sets the document title
- // content for this welcome page
-
-
-
-
-
-
-
-
+
}
}
-
-/// Renders the home page of your application.
-#[component]
-fn HomePage(cx: Scope) -> impl IntoView {
- // Creates a reactive value to update the button
- let (count, set_count) = create_signal(cx, 0);
- let on_click = move |_| set_count.update(|count| *count += 1);
-
- view! { cx,
- "Welcome to Leptos!"
-
- "Click Me: "
- {count}
-
- }
-}
-
-/// 404 - Not Found
-#[component]
-fn NotFound(cx: Scope) -> impl IntoView {
- // set an HTTP status code 404
- // this is feature gated because it can only be done during
- // initial server-side rendering
- // if you navigate to the 404 page subsequently, the status
- // code will not be set because there is not a new HTTP request
- // to the server
- #[cfg(feature = "ssr")]
- {
- // this can be done inline because it's synchronous
- // if it were async, we'd use a server function
- let resp = expect_context::(cx);
- resp.set_status(actix_web::http::StatusCode::NOT_FOUND);
- }
-
- view! { cx, "Not Found" }
-}
diff --git a/crates/website/src/lib.rs b/crates/website/src/lib.rs
index b3dba96d..8fba6329 100644
--- a/crates/website/src/lib.rs
+++ b/crates/website/src/lib.rs
@@ -1,4 +1,5 @@
pub mod app;
+pub mod site;
#[cfg(feature = "hydrate")]
use wasm_bindgen::prelude::wasm_bindgen;
diff --git a/crates/website/src/site/components/mod.rs b/crates/website/src/site/components/mod.rs
new file mode 100644
index 00000000..7b062f5c
--- /dev/null
+++ b/crates/website/src/site/components/mod.rs
@@ -0,0 +1,3 @@
+mod navbar;
+
+pub use navbar::NavBar;
diff --git a/crates/website/src/site/components/navbar.rs b/crates/website/src/site/components/navbar.rs
new file mode 100644
index 00000000..b1bb310a
--- /dev/null
+++ b/crates/website/src/site/components/navbar.rs
@@ -0,0 +1,33 @@
+use leptos::*;
+
+#[component]
+pub fn NavBar(cx: Scope) -> impl IntoView {
+ view! { cx,
+
+ }
+}
diff --git a/crates/website/src/site/errors/mod.rs b/crates/website/src/site/errors/mod.rs
new file mode 100644
index 00000000..41445dbd
--- /dev/null
+++ b/crates/website/src/site/errors/mod.rs
@@ -0,0 +1 @@
+pub mod not_found;
diff --git a/crates/website/src/site/errors/not_found.rs b/crates/website/src/site/errors/not_found.rs
new file mode 100644
index 00000000..770321b1
--- /dev/null
+++ b/crates/website/src/site/errors/not_found.rs
@@ -0,0 +1,20 @@
+use leptos::*;
+
+#[component]
+pub fn NotFound(cx: Scope) -> impl IntoView {
+ // set an HTTP status code 404
+ // this is feature gated because it can only be done during
+ // initial server-side rendering
+ // if you navigate to the 404 page subsequently, the status
+ // code will not be set because there is not a new HTTP request
+ // to the server
+ #[cfg(feature = "ssr")]
+ {
+ // this can be done inline because it's synchronous
+ // if it were async, we'd use a server function
+ let resp = expect_context::(cx);
+ resp.set_status(actix_web::http::StatusCode::NOT_FOUND);
+ }
+
+ view! { cx, "Not Found" }
+}
diff --git a/crates/website/src/site/mod.rs b/crates/website/src/site/mod.rs
new file mode 100644
index 00000000..6b05f2f2
--- /dev/null
+++ b/crates/website/src/site/mod.rs
@@ -0,0 +1,3 @@
+pub mod components;
+pub mod errors;
+pub mod routes;
diff --git a/crates/website/src/site/routes/dashboard/mod.rs b/crates/website/src/site/routes/dashboard/mod.rs
new file mode 100644
index 00000000..d66e26b0
--- /dev/null
+++ b/crates/website/src/site/routes/dashboard/mod.rs
@@ -0,0 +1,8 @@
+pub mod server_list;
+
+use leptos::*;
+
+#[component]
+pub fn Dashboard(cx: Scope) -> impl IntoView {
+ view! { cx, "dashboard index"
}
+}
diff --git a/crates/website/src/site/routes/dashboard/server_list.rs b/crates/website/src/site/routes/dashboard/server_list.rs
new file mode 100644
index 00000000..6ed25213
--- /dev/null
+++ b/crates/website/src/site/routes/dashboard/server_list.rs
@@ -0,0 +1,10 @@
+use leptos::*;
+
+#[component]
+pub fn ServerList(cx: Scope) -> impl IntoView {
+ view! { cx,
+
+ Hello, world!
+
+ }
+}
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
new file mode 100644
index 00000000..a6cf1d62
--- /dev/null
+++ b/crates/website/src/site/routes/mod.rs
@@ -0,0 +1,41 @@
+pub mod website;
+pub mod dashboard;
+
+use leptos::*;
+use leptos_router::*;
+
+use super::errors;
+
+#[component]
+pub fn Index(cx: Scope) -> impl IntoView {
+ view! { cx,
+
+
+
+
+
+
+
+
+
+
+
+
+
+ //
+ //
+ //
+ //
+ //
+ // // ...other setting categories
+ // // requirements, behavior, embed, style, regex, filters
+ //
+ //
+
+
+
+
+
+
+ }
+}
diff --git a/crates/website/src/site/routes/website/home.rs b/crates/website/src/site/routes/website/home.rs
new file mode 100644
index 00000000..6f77d67a
--- /dev/null
+++ b/crates/website/src/site/routes/website/home.rs
@@ -0,0 +1,15 @@
+use leptos::*;
+
+#[component]
+pub fn Home(cx: Scope) -> impl IntoView {
+ let (count, set_count) = create_signal(cx, 0);
+ let on_click = move |_| set_count.update(|count| *count += 1);
+
+ view! { cx,
+ "Welcome to Leptos!"
+
+ "Click Me: "
+ {count}
+
+ }
+}
diff --git a/crates/website/src/site/routes/website/mod.rs b/crates/website/src/site/routes/website/mod.rs
new file mode 100644
index 00000000..c55f7bd2
--- /dev/null
+++ b/crates/website/src/site/routes/website/mod.rs
@@ -0,0 +1,14 @@
+pub mod home;
+
+use leptos::*;
+
+use crate::site::components::NavBar;
+
+#[component]
+pub fn Website(cx: Scope) -> impl IntoView {
+ view! { cx,
+
+
+
+ }
+}
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
index a5e8e5c3..a83b0bca 100644
--- a/crates/website/style/output.css
+++ b/crates/website/style/output.css
@@ -698,6 +698,17 @@ html {
--tw-backdrop-sepia: ;
}
+@media (hover:hover) {
+ .menu li > *:not(ul):not(.menu-title):not(details):active,
+.menu li > *:not(ul):not(.menu-title):not(details).active,
+.menu li > details > summary:active {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--n) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--nc) / var(--tw-text-opacity));
+ }
+}
+
.btn {
display: inline-flex;
flex-shrink: 0;
@@ -777,11 +788,33 @@ html {
background-color: hsl(var(--b3) / var(--tw-bg-opacity));
}
+ .btn-primary:hover {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--pf) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--pf) / var(--tw-bg-opacity));
+ }
+
.btn.glass:hover {
--glass-opacity: 25%;
--glass-border-opacity: 15%;
}
+ .btn-ghost:hover {
+ --tw-border-opacity: 0;
+ background-color: hsl(var(--bc) / var(--tw-bg-opacity));
+ --tw-bg-opacity: 0.2;
+ }
+
+ .btn-outline.btn-primary:hover {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--pf) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--pf) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--pc) / var(--tw-text-opacity));
+ }
+
.btn-disabled:hover,
.btn[disabled]:hover,
.btn:disabled:hover {
@@ -798,6 +831,82 @@ html {
--tw-bg-opacity: 1;
background-color: hsl(var(--pf) / var(--tw-bg-opacity));
}
+
+ :where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):not(.active):hover, :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):not(.active):hover {
+ cursor: pointer;
+ background-color: hsl(var(--bc) / 0.1);
+ --tw-text-opacity: 1;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+ }
+}
+
+.menu {
+ display: flex;
+ flex-direction: column;
+ flex-wrap: wrap;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ padding: 0.5rem;
+}
+
+.menu :where(li ul) {
+ position: relative;
+ white-space: nowrap;
+ margin-left: 1rem;
+ padding-left: 0.5rem;
+}
+
+.menu :where(li:not(.menu-title) > *:not(ul):not(details):not(.menu-title)),
+ .menu :where(li:not(.menu-title) > details > summary:not(.menu-title)) {
+ display: grid;
+ grid-auto-flow: column;
+ align-content: flex-start;
+ align-items: center;
+ gap: 0.5rem;
+ grid-auto-columns: minmax(auto, max-content) auto max-content;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+}
+
+.menu li.disabled {
+ cursor: not-allowed;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+ color: hsl(var(--bc) / 0.3);
+}
+
+.menu :where(li > .menu-dropdown:not(.menu-dropdown-show)) {
+ display: none;
+}
+
+:where(.menu li) {
+ position: relative;
+ display: flex;
+ flex-shrink: 0;
+ flex-direction: column;
+ flex-wrap: wrap;
+ align-items: stretch;
+}
+
+:where(.menu li) .badge {
+ justify-self: end;
+}
+
+.navbar {
+ display: flex;
+ align-items: center;
+ padding: var(--navbar-padding, 0.5rem);
+ min-height: 4rem;
+ width: 100%;
+}
+
+:where(.navbar > *) {
+ display: inline-flex;
+ align-items: center;
}
.btn:active:hover,
@@ -812,6 +921,23 @@ html {
outline-offset: 2px;
}
+.btn-primary {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--p) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--p) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--pc) / var(--tw-text-opacity));
+ outline-color: hsl(var(--p) / 1);
+}
+
+.btn-primary.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--pf) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--pf) / var(--tw-bg-opacity));
+}
+
.btn.glass {
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
@@ -824,6 +950,37 @@ html {
--glass-border-opacity: 15%;
}
+.btn-ghost {
+ border-width: 1px;
+ border-color: transparent;
+ background-color: transparent;
+ color: currentColor;
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-colored: 0 0 #0000;
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
+ outline-color: currentColor;
+}
+
+.btn-ghost.btn-active {
+ --tw-border-opacity: 0;
+ background-color: hsl(var(--bc) / var(--tw-bg-opacity));
+ --tw-bg-opacity: 0.2;
+}
+
+.btn-outline.btn-primary {
+ --tw-text-opacity: 1;
+ color: hsl(var(--p) / var(--tw-text-opacity));
+}
+
+.btn-outline.btn-primary.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--pf) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--pf) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--pc) / var(--tw-text-opacity));
+}
+
.btn.btn-disabled,
.btn[disabled],
.btn:disabled {
@@ -892,6 +1049,89 @@ html {
}
}
+:where(.menu li:empty) {
+ background-color: hsl(var(--bc) / 0.1);
+ margin: 0.5rem 1rem;
+ height: 1px;
+}
+
+.menu :where(li ul):before {
+ position: absolute;
+ left: 0px;
+ top: 0.75rem;
+ bottom: 0.75rem;
+ width: 1px;
+ background-color: hsl(var(--bc) / 0.1);
+ content: "";
+}
+
+.menu :where(li:not(.menu-title) > *:not(ul):not(details):not(.menu-title)),
+.menu :where(li:not(.menu-title) > details > summary:not(.menu-title)) {
+ padding-left: 1rem;
+ padding-right: 1rem;
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+ text-align: left;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ transition-duration: 200ms;
+ border-radius: var(--rounded-btn, 0.5rem);
+ text-wrap: balance;
+}
+
+:where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):not(summary):not(.active).focus,
+ :where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):not(summary):not(.active):focus,
+ :where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):is(summary):not(.active):focus-visible,
+ :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):not(summary):not(.active).focus,
+ :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):not(summary):not(.active):focus,
+ :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):is(summary):not(.active):focus-visible {
+ cursor: pointer;
+ background-color: hsl(var(--bc) / 0.1);
+ --tw-text-opacity: 1;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+}
+
+.menu li > *:not(ul):not(.menu-title):not(details):active,
+.menu li > *:not(ul):not(.menu-title):not(details).active,
+.menu li > details > summary:active {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--n) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--nc) / var(--tw-text-opacity));
+}
+
+.menu :where(li > details > summary)::-webkit-details-marker {
+ display: none;
+}
+
+.menu :where(li > details > summary):after,
+.menu :where(li > .menu-dropdown-toggle):after {
+ justify-self: end;
+ display: block;
+ margin-top: -0.5rem;
+ height: 0.5rem;
+ width: 0.5rem;
+ transform: rotate(45deg);
+ transition-property: transform, margin-top;
+ transition-duration: 0.3s;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ content: "";
+ transform-origin: 75% 75%;
+ box-shadow: 2px 2px;
+ pointer-events: none;
+}
+
+.menu :where(li > details[open] > summary):after,
+.menu :where(li > .menu-dropdown-toggle.menu-dropdown-show):after {
+ transform: rotate(225deg);
+ margin-top: 0;
+}
+
@keyframes modal-pop {
0% {
opacity: 0;
@@ -944,6 +1184,36 @@ html {
}
}
+.btn-sm {
+ height: 2rem;
+ padding-left: 0.75rem;
+ padding-right: 0.75rem;
+ min-height: 2rem;
+ font-size: 0.875rem;
+}
+
+.btn-square:where(.btn-sm) {
+ height: 2rem;
+ width: 2rem;
+ padding: 0px;
+}
+
+.btn-circle:where(.btn-sm) {
+ height: 2rem;
+ width: 2rem;
+ border-radius: 9999px;
+ padding: 0px;
+}
+
+.menu-horizontal {
+ display: inline-flex;
+ flex-direction: row;
+}
+
+.menu-horizontal > li:not(.menu-title) > details > ul {
+ position: absolute;
+}
+
.btn-group .btn:not(:first-child):not(:last-child) {
border-top-left-radius: 0;
border-top-right-radius: 0;
@@ -1006,6 +1276,62 @@ html {
border-bottom-right-radius: var(--rounded-btn, 0.5rem);
}
+.menu-horizontal > li:not(.menu-title) > details > ul {
+ margin-top: 1rem;
+ margin-left: 0px;
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+ padding-right: 0.5rem;
+}
+
+.menu-horizontal > li > details > ul:before {
+ content: none;
+}
+
+:where(.menu-horizontal > li:not(.menu-title) > details > ul) {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b1) / var(--tw-bg-opacity));
+ --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
+ --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
+ border-radius: var(--rounded-box, 1rem);
+}
+
.inline {
display: inline;
}
+
+.flex-1 {
+ flex: 1 1 0%;
+}
+
+.flex-none {
+ flex: none;
+}
+
+.justify-center {
+ justify-content: center;
+}
+
+.bg-base-100 {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b1) / var(--tw-bg-opacity));
+}
+
+.p-2 {
+ padding: 0.5rem;
+}
+
+.px-1 {
+ padding-left: 0.25rem;
+ padding-right: 0.25rem;
+}
+
+.text-xl {
+ font-size: 1.25rem;
+ line-height: 1.75rem;
+}
+
+.normal-case {
+ text-transform: none;
+}
From 20346a9a5170ceced64ce9151d6997ff2d54c802 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 18:42:52 -0400
Subject: [PATCH 011/119] outsource route definitions
---
crates/website/src/site/routes/mod.rs | 60 ++++++++++++++++-----------
1 file changed, 36 insertions(+), 24 deletions(-)
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index a6cf1d62..1441354b 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -11,31 +11,43 @@ pub fn Index(cx: Scope) -> impl IntoView {
view! { cx,
-
-
-
-
-
-
-
-
-
-
-
- //
- //
- //
- //
- //
- // // ...other setting categories
- // // requirements, behavior, embed, style, regex, filters
- //
- //
-
-
-
-
+
+
}
}
+
+#[component(transparent)]
+fn WebsiteRoutes(cx: Scope) -> impl IntoView {
+ view! { cx,
+
+
+
+
+
+
+
+ }
+}
+
+#[component(transparent)]
+fn DashboardRoutes(cx: Scope) -> impl IntoView {
+ view! { cx,
+
+
+
+ //
+ //
+ //
+ //
+ //
+
+ //
+ //
+
+
+
+
+ }
+}
From 4d1ccc1bb4bd43c0727f33db3af9b755f49e9c01 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 18:48:59 -0400
Subject: [PATCH 012/119] needed Outlet
---
.../website/src/site/routes/dashboard/mod.rs | 10 ++++++-
crates/website/src/site/routes/mod.rs | 30 ++++++++-----------
crates/website/src/site/routes/website/mod.rs | 4 +++
3 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/crates/website/src/site/routes/dashboard/mod.rs b/crates/website/src/site/routes/dashboard/mod.rs
index d66e26b0..d2c07ba2 100644
--- a/crates/website/src/site/routes/dashboard/mod.rs
+++ b/crates/website/src/site/routes/dashboard/mod.rs
@@ -1,8 +1,16 @@
pub mod server_list;
use leptos::*;
+use leptos_router::Outlet;
#[component]
pub fn Dashboard(cx: Scope) -> impl IntoView {
- view! { cx, "dashboard index"
}
+ view! { cx,
+
+ "dashboard navbar"
+
+
+
+
+ }
}
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index 1441354b..70ca94bc 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -22,11 +22,9 @@ pub fn Index(cx: Scope) -> impl IntoView {
fn WebsiteRoutes(cx: Scope) -> impl IntoView {
view! { cx,
-
-
+
-
-
+
}
}
@@ -35,19 +33,17 @@ fn WebsiteRoutes(cx: Scope) -> impl IntoView {
fn DashboardRoutes(cx: Scope) -> impl IntoView {
view! { cx,
-
-
- //
- //
- //
- //
- //
-
- //
- //
-
-
-
+
+ //
+ //
+ //
+ //
+ //
+
+ //
+ //
+
+
}
}
diff --git a/crates/website/src/site/routes/website/mod.rs b/crates/website/src/site/routes/website/mod.rs
index c55f7bd2..bdef3961 100644
--- a/crates/website/src/site/routes/website/mod.rs
+++ b/crates/website/src/site/routes/website/mod.rs
@@ -1,6 +1,7 @@
pub mod home;
use leptos::*;
+use leptos_router::Outlet;
use crate::site::components::NavBar;
@@ -10,5 +11,8 @@ pub fn Website(cx: Scope) -> impl IntoView {
+
+
+
}
}
From 5ec39a7154df725da6b804756a589526fa77e170 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 19:13:05 -0400
Subject: [PATCH 013/119] custom theme
---
crates/website/style/output.css | 362 ++----------------------------
crates/website/tailwind.config.js | 18 +-
2 files changed, 36 insertions(+), 344 deletions(-)
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
index a83b0bca..30b6ff0e 100644
--- a/crates/website/style/output.css
+++ b/crates/website/style/output.css
@@ -445,97 +445,22 @@ html {
}
:root {
- color-scheme: light;
- --pf: 259 94% 44%;
- --sf: 314 100% 40%;
- --af: 174 75% 39%;
- --nf: 214 20% 14%;
- --in: 198 93% 60%;
- --su: 158 64% 52%;
- --wa: 43 96% 56%;
- --er: 0 91% 71%;
- --inc: 198 100% 12%;
- --suc: 158 100% 10%;
- --wac: 43 100% 11%;
- --erc: 0 100% 14%;
- --rounded-box: 1rem;
- --rounded-btn: 0.5rem;
- --rounded-badge: 1.9rem;
- --animation-btn: 0.25s;
- --animation-input: .2s;
- --btn-text-case: uppercase;
- --btn-focus-scale: 0.95;
- --border-btn: 1px;
- --tab-border: 1px;
- --tab-radius: 0.5rem;
- --p: 259 94% 51%;
- --pc: 259 96% 91%;
- --s: 314 100% 47%;
- --sc: 314 100% 91%;
- --a: 174 75% 46%;
- --ac: 174 75% 11%;
- --n: 214 20% 21%;
- --nc: 212 19% 87%;
- --b1: 0 0% 100%;
- --b2: 0 0% 95%;
- --b3: 180 2% 90%;
- --bc: 215 28% 17%;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- color-scheme: dark;
- --pf: 262 80% 43%;
- --sf: 316 70% 43%;
- --af: 175 70% 34%;
- --in: 198 93% 60%;
- --su: 158 64% 52%;
- --wa: 43 96% 56%;
- --er: 0 91% 71%;
- --inc: 198 100% 12%;
- --suc: 158 100% 10%;
- --wac: 43 100% 11%;
- --erc: 0 100% 14%;
- --rounded-box: 1rem;
- --rounded-btn: 0.5rem;
- --rounded-badge: 1.9rem;
- --animation-btn: 0.25s;
- --animation-input: .2s;
- --btn-text-case: uppercase;
- --btn-focus-scale: 0.95;
- --border-btn: 1px;
- --tab-border: 1px;
- --tab-radius: 0.5rem;
- --p: 262 80% 50%;
- --pc: 0 0% 100%;
- --s: 316 70% 50%;
- --sc: 0 0% 100%;
- --a: 175 70% 41%;
- --ac: 0 0% 100%;
- --n: 213 18% 20%;
- --nf: 212 17% 17%;
- --nc: 220 13% 69%;
- --b1: 212 18% 14%;
- --b2: 213 18% 12%;
- --b3: 213 18% 10%;
- --bc: 220 13% 69%;
- }
-}
-
-[data-theme=light] {
- color-scheme: light;
- --pf: 259 94% 44%;
- --sf: 314 100% 40%;
- --af: 174 75% 39%;
- --nf: 214 20% 14%;
- --in: 198 93% 60%;
- --su: 158 64% 52%;
- --wa: 43 96% 56%;
- --er: 0 91% 71%;
- --inc: 198 100% 12%;
- --suc: 158 100% 10%;
- --wac: 43 100% 11%;
- --erc: 0 100% 14%;
+ --p: 42 100% 81%;
+ --pf: 42 100% 74%;
+ --sf: 292 91% 66%;
+ --af: 187 92% 62%;
+ --nf: 213 18% 13%;
+ --b2: 212 18% 7%;
+ --b3: 0 0% 0%;
+ --bc: 214 3% 81%;
+ --pc: 41 18% 16%;
+ --sc: 294 25% 15%;
+ --ac: 187 26% 15%;
+ --nc: 215 5% 82%;
+ --inc: 202 34% 14%;
+ --suc: 152 31% 13%;
+ --wac: 39 47% 13%;
+ --erc: 3 29% 15%;
--rounded-box: 1rem;
--rounded-btn: 0.5rem;
--rounded-badge: 1.9rem;
@@ -546,56 +471,14 @@ html {
--border-btn: 1px;
--tab-border: 1px;
--tab-radius: 0.5rem;
- --p: 259 94% 51%;
- --pc: 259 96% 91%;
- --s: 314 100% 47%;
- --sc: 314 100% 91%;
- --a: 174 75% 46%;
- --ac: 174 75% 11%;
- --n: 214 20% 21%;
- --nc: 212 19% 87%;
- --b1: 0 0% 100%;
- --b2: 0 0% 95%;
- --b3: 180 2% 90%;
- --bc: 215 28% 17%;
-}
-
-[data-theme=dark] {
- color-scheme: dark;
- --pf: 262 80% 43%;
- --sf: 316 70% 43%;
- --af: 175 70% 34%;
+ --s: 292 91% 73%;
+ --a: 187 92% 69%;
+ --n: 213 18% 20%;
+ --b1: 212 18% 14%;
--in: 198 93% 60%;
--su: 158 64% 52%;
--wa: 43 96% 56%;
--er: 0 91% 71%;
- --inc: 198 100% 12%;
- --suc: 158 100% 10%;
- --wac: 43 100% 11%;
- --erc: 0 100% 14%;
- --rounded-box: 1rem;
- --rounded-btn: 0.5rem;
- --rounded-badge: 1.9rem;
- --animation-btn: 0.25s;
- --animation-input: .2s;
- --btn-text-case: uppercase;
- --btn-focus-scale: 0.95;
- --border-btn: 1px;
- --tab-border: 1px;
- --tab-radius: 0.5rem;
- --p: 262 80% 50%;
- --pc: 0 0% 100%;
- --s: 316 70% 50%;
- --sc: 0 0% 100%;
- --a: 175 70% 41%;
- --ac: 0 0% 100%;
- --n: 213 18% 20%;
- --nf: 212 17% 17%;
- --nc: 220 13% 69%;
- --b1: 212 18% 14%;
- --b2: 213 18% 12%;
- --b3: 213 18% 10%;
- --bc: 220 13% 69%;
}
*, ::before, ::after {
@@ -698,17 +581,6 @@ html {
--tw-backdrop-sepia: ;
}
-@media (hover:hover) {
- .menu li > *:not(ul):not(.menu-title):not(details):active,
-.menu li > *:not(ul):not(.menu-title):not(details).active,
-.menu li > details > summary:active {
- --tw-bg-opacity: 1;
- background-color: hsl(var(--n) / var(--tw-bg-opacity));
- --tw-text-opacity: 1;
- color: hsl(var(--nc) / var(--tw-text-opacity));
- }
-}
-
.btn {
display: inline-flex;
flex-shrink: 0;
@@ -831,69 +703,6 @@ html {
--tw-bg-opacity: 1;
background-color: hsl(var(--pf) / var(--tw-bg-opacity));
}
-
- :where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):not(.active):hover, :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):not(.active):hover {
- cursor: pointer;
- background-color: hsl(var(--bc) / 0.1);
- --tw-text-opacity: 1;
- color: hsl(var(--bc) / var(--tw-text-opacity));
- outline: 2px solid transparent;
- outline-offset: 2px;
- }
-}
-
-.menu {
- display: flex;
- flex-direction: column;
- flex-wrap: wrap;
- font-size: 0.875rem;
- line-height: 1.25rem;
- padding: 0.5rem;
-}
-
-.menu :where(li ul) {
- position: relative;
- white-space: nowrap;
- margin-left: 1rem;
- padding-left: 0.5rem;
-}
-
-.menu :where(li:not(.menu-title) > *:not(ul):not(details):not(.menu-title)),
- .menu :where(li:not(.menu-title) > details > summary:not(.menu-title)) {
- display: grid;
- grid-auto-flow: column;
- align-content: flex-start;
- align-items: center;
- gap: 0.5rem;
- grid-auto-columns: minmax(auto, max-content) auto max-content;
- -webkit-user-select: none;
- -moz-user-select: none;
- user-select: none;
-}
-
-.menu li.disabled {
- cursor: not-allowed;
- -webkit-user-select: none;
- -moz-user-select: none;
- user-select: none;
- color: hsl(var(--bc) / 0.3);
-}
-
-.menu :where(li > .menu-dropdown:not(.menu-dropdown-show)) {
- display: none;
-}
-
-:where(.menu li) {
- position: relative;
- display: flex;
- flex-shrink: 0;
- flex-direction: column;
- flex-wrap: wrap;
- align-items: stretch;
-}
-
-:where(.menu li) .badge {
- justify-self: end;
}
.navbar {
@@ -1049,89 +858,6 @@ html {
}
}
-:where(.menu li:empty) {
- background-color: hsl(var(--bc) / 0.1);
- margin: 0.5rem 1rem;
- height: 1px;
-}
-
-.menu :where(li ul):before {
- position: absolute;
- left: 0px;
- top: 0.75rem;
- bottom: 0.75rem;
- width: 1px;
- background-color: hsl(var(--bc) / 0.1);
- content: "";
-}
-
-.menu :where(li:not(.menu-title) > *:not(ul):not(details):not(.menu-title)),
-.menu :where(li:not(.menu-title) > details > summary:not(.menu-title)) {
- padding-left: 1rem;
- padding-right: 1rem;
- padding-top: 0.5rem;
- padding-bottom: 0.5rem;
- text-align: left;
- transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
- transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
- transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
- transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
- transition-duration: 200ms;
- border-radius: var(--rounded-btn, 0.5rem);
- text-wrap: balance;
-}
-
-:where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):not(summary):not(.active).focus,
- :where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):not(summary):not(.active):focus,
- :where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):is(summary):not(.active):focus-visible,
- :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):not(summary):not(.active).focus,
- :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):not(summary):not(.active):focus,
- :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):is(summary):not(.active):focus-visible {
- cursor: pointer;
- background-color: hsl(var(--bc) / 0.1);
- --tw-text-opacity: 1;
- color: hsl(var(--bc) / var(--tw-text-opacity));
- outline: 2px solid transparent;
- outline-offset: 2px;
-}
-
-.menu li > *:not(ul):not(.menu-title):not(details):active,
-.menu li > *:not(ul):not(.menu-title):not(details).active,
-.menu li > details > summary:active {
- --tw-bg-opacity: 1;
- background-color: hsl(var(--n) / var(--tw-bg-opacity));
- --tw-text-opacity: 1;
- color: hsl(var(--nc) / var(--tw-text-opacity));
-}
-
-.menu :where(li > details > summary)::-webkit-details-marker {
- display: none;
-}
-
-.menu :where(li > details > summary):after,
-.menu :where(li > .menu-dropdown-toggle):after {
- justify-self: end;
- display: block;
- margin-top: -0.5rem;
- height: 0.5rem;
- width: 0.5rem;
- transform: rotate(45deg);
- transition-property: transform, margin-top;
- transition-duration: 0.3s;
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
- content: "";
- transform-origin: 75% 75%;
- box-shadow: 2px 2px;
- pointer-events: none;
-}
-
-.menu :where(li > details[open] > summary):after,
-.menu :where(li > .menu-dropdown-toggle.menu-dropdown-show):after {
- transform: rotate(225deg);
- margin-top: 0;
-}
-
@keyframes modal-pop {
0% {
opacity: 0;
@@ -1205,15 +931,6 @@ html {
padding: 0px;
}
-.menu-horizontal {
- display: inline-flex;
- flex-direction: row;
-}
-
-.menu-horizontal > li:not(.menu-title) > details > ul {
- position: absolute;
-}
-
.btn-group .btn:not(:first-child):not(:last-child) {
border-top-left-radius: 0;
border-top-right-radius: 0;
@@ -1276,27 +993,6 @@ html {
border-bottom-right-radius: var(--rounded-btn, 0.5rem);
}
-.menu-horizontal > li:not(.menu-title) > details > ul {
- margin-top: 1rem;
- margin-left: 0px;
- padding-top: 0.5rem;
- padding-bottom: 0.5rem;
- padding-right: 0.5rem;
-}
-
-.menu-horizontal > li > details > ul:before {
- content: none;
-}
-
-:where(.menu-horizontal > li:not(.menu-title) > details > ul) {
- --tw-bg-opacity: 1;
- background-color: hsl(var(--b1) / var(--tw-bg-opacity));
- --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
- --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
- box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
- border-radius: var(--rounded-box, 1rem);
-}
-
.inline {
display: inline;
}
@@ -1305,28 +1001,10 @@ html {
flex: 1 1 0%;
}
-.flex-none {
- flex: none;
-}
-
.justify-center {
justify-content: center;
}
-.bg-base-100 {
- --tw-bg-opacity: 1;
- background-color: hsl(var(--b1) / var(--tw-bg-opacity));
-}
-
-.p-2 {
- padding: 0.5rem;
-}
-
-.px-1 {
- padding-left: 0.25rem;
- padding-right: 0.25rem;
-}
-
.text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
diff --git a/crates/website/tailwind.config.js b/crates/website/tailwind.config.js
index cab7f06a..c026041f 100644
--- a/crates/website/tailwind.config.js
+++ b/crates/website/tailwind.config.js
@@ -3,8 +3,22 @@ module.exports = {
content: {
files: ["*.html", "./src/**/*.rs"],
},
- theme: {
- extend: {},
+ daisyui: {
+ themes: [
+ {
+ dark: {
+ primary: "#ffe19c",
+ secondary: "#e879f9",
+ accent: "#67e8f9",
+ neutral: "#2a323c",
+ "base-100": "#1d232a",
+ info: "#3abff8",
+ success: "#36d399",
+ warning: "#fbbd23",
+ error: "#f87272",
+ },
+ },
+ ],
},
plugins: [require("daisyui")],
};
From fbcf5de2bb91a67c19caf5eb28fe1348579d5ffb Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 20:36:49 -0400
Subject: [PATCH 014/119] stuff
---
Cargo.lock | 37 +++++++++++++++++++
crates/website/Cargo.toml | 1 +
crates/website/src/lib.rs | 1 +
crates/website/src/site/components/navbar.rs | 6 +--
crates/website/src/site/mod.rs | 2 +
.../website/src/site/routes/dashboard/mod.rs | 16 --------
.../src/site/routes/dashboard/server_list.rs | 10 -----
crates/website/src/site/routes/mod.rs | 19 +++++-----
.../website/src/site/routes/servers/id/mod.rs | 36 ++++++++++++++++++
crates/website/src/site/routes/servers/mod.rs | 10 +++++
.../src/site/routes/servers/server_list.rs | 18 +++++++++
crates/website/src/utils/icon.rs | 6 +++
crates/website/src/utils/mod.rs | 1 +
crates/website/style/output.css | 15 ++++++++
14 files changed, 139 insertions(+), 39 deletions(-)
delete mode 100644 crates/website/src/site/routes/dashboard/mod.rs
delete mode 100644 crates/website/src/site/routes/dashboard/server_list.rs
create mode 100644 crates/website/src/site/routes/servers/id/mod.rs
create mode 100644 crates/website/src/site/routes/servers/mod.rs
create mode 100644 crates/website/src/site/routes/servers/server_list.rs
create mode 100644 crates/website/src/utils/icon.rs
create mode 100644 crates/website/src/utils/mod.rs
diff --git a/Cargo.lock b/Cargo.lock
index f27c152b..bed7e37d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1658,6 +1658,31 @@ dependencies = [
"cc",
]
+[[package]]
+name = "icondata"
+version = "0.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ffb16cf8cbf74c05967c0c12b492a10ad23d3511abdc77bc43c142004e3d435"
+dependencies = [
+ "icondata_core",
+ "icondata_fa",
+]
+
+[[package]]
+name = "icondata_core"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1640a4c1d5ddd08ab1d9854ffa7a2fa3dc52339492676b6d3031e77ca579f434"
+
+[[package]]
+name = "icondata_fa"
+version = "0.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "029f6e7f84560b8b4543c06ddd68a79839397672203efebd50d4364898de3c13"
+dependencies = [
+ "icondata_core",
+]
+
[[package]]
name = "ident_case"
version = "1.0.1"
@@ -1886,6 +1911,17 @@ dependencies = [
"walkdir",
]
+[[package]]
+name = "leptos_icons"
+version = "0.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c4cbfd152ac2449509618939d69b4ee5ea4e1b8697ca57c447021a9d84632e2"
+dependencies = [
+ "icondata",
+ "leptos",
+ "tracing",
+]
+
[[package]]
name = "leptos_integration_utils"
version = "0.4.8"
@@ -4411,6 +4447,7 @@ dependencies = [
"http",
"leptos",
"leptos_actix",
+ "leptos_icons",
"leptos_meta",
"leptos_router",
"wasm-bindgen",
diff --git a/crates/website/Cargo.toml b/crates/website/Cargo.toml
index 570f70bf..09d2e31b 100644
--- a/crates/website/Cargo.toml
+++ b/crates/website/Cargo.toml
@@ -17,6 +17,7 @@ leptos_meta = { version = "0.4", features = ["nightly"] }
leptos_actix = { version = "0.4", optional = true }
leptos_router = { version = "0.4", features = ["nightly"] }
wasm-bindgen = "=0.2.87"
+leptos_icons = { version = "0.0.15", features = ["FaChevronLeftSolid"] }
[features]
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
diff --git a/crates/website/src/lib.rs b/crates/website/src/lib.rs
index 8fba6329..e62fc3a6 100644
--- a/crates/website/src/lib.rs
+++ b/crates/website/src/lib.rs
@@ -1,5 +1,6 @@
pub mod app;
pub mod site;
+pub mod utils;
#[cfg(feature = "hydrate")]
use wasm_bindgen::prelude::wasm_bindgen;
diff --git a/crates/website/src/site/components/navbar.rs b/crates/website/src/site/components/navbar.rs
index b1bb310a..7817cda5 100644
--- a/crates/website/src/site/components/navbar.rs
+++ b/crates/website/src/site/components/navbar.rs
@@ -5,7 +5,7 @@ pub fn NavBar(cx: Scope) -> impl IntoView {
view! { cx,
@@ -24,8 +24,8 @@ pub fn NavBar(cx: Scope) -> impl IntoView {
diff --git a/crates/website/src/site/mod.rs b/crates/website/src/site/mod.rs
index 6b05f2f2..fa3484d4 100644
--- a/crates/website/src/site/mod.rs
+++ b/crates/website/src/site/mod.rs
@@ -1,3 +1,5 @@
+#![allow(unused_braces)]
+
pub mod components;
pub mod errors;
pub mod routes;
diff --git a/crates/website/src/site/routes/dashboard/mod.rs b/crates/website/src/site/routes/dashboard/mod.rs
deleted file mode 100644
index d2c07ba2..00000000
--- a/crates/website/src/site/routes/dashboard/mod.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-pub mod server_list;
-
-use leptos::*;
-use leptos_router::Outlet;
-
-#[component]
-pub fn Dashboard(cx: Scope) -> impl IntoView {
- view! { cx,
-
- "dashboard navbar"
-
-
-
-
- }
-}
diff --git a/crates/website/src/site/routes/dashboard/server_list.rs b/crates/website/src/site/routes/dashboard/server_list.rs
deleted file mode 100644
index 6ed25213..00000000
--- a/crates/website/src/site/routes/dashboard/server_list.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use leptos::*;
-
-#[component]
-pub fn ServerList(cx: Scope) -> impl IntoView {
- view! { cx,
-
- Hello, world!
-
- }
-}
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index 70ca94bc..88fdf047 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -1,5 +1,5 @@
+pub mod servers;
pub mod website;
-pub mod dashboard;
use leptos::*;
use leptos_router::*;
@@ -32,15 +32,14 @@ fn WebsiteRoutes(cx: Scope) -> impl IntoView {
#[component(transparent)]
fn DashboardRoutes(cx: Scope) -> impl IntoView {
view! { cx,
-
-
- //
- //
- //
- //
- //
-
- //
+
+
+
+ //
+ //
+ //
+ //
+
//
diff --git a/crates/website/src/site/routes/servers/id/mod.rs b/crates/website/src/site/routes/servers/id/mod.rs
new file mode 100644
index 00000000..d13a6039
--- /dev/null
+++ b/crates/website/src/site/routes/servers/id/mod.rs
@@ -0,0 +1,36 @@
+use leptos::*;
+use leptos_icons::*;
+use leptos_router::*;
+
+#[derive(Params, PartialEq)]
+struct Props {
+ id: i64,
+}
+
+#[component]
+pub fn Server(cx: Scope) -> impl IntoView {
+ let params = use_params::(cx);
+
+ let id = move || params.with(|p| p.as_ref().unwrap().id);
+
+ view! { cx,
+
+
+
+ {id}
+ }
+}
+
+#[component]
+fn ServerNavBar(cx: Scope) -> impl IntoView {
+ view! { cx,
+
+ }
+}
diff --git a/crates/website/src/site/routes/servers/mod.rs b/crates/website/src/site/routes/servers/mod.rs
new file mode 100644
index 00000000..1e4faa7d
--- /dev/null
+++ b/crates/website/src/site/routes/servers/mod.rs
@@ -0,0 +1,10 @@
+pub mod id;
+pub mod server_list;
+
+use leptos::*;
+use leptos_router::Outlet;
+
+#[component]
+pub fn Servers(cx: Scope) -> impl IntoView {
+ view! { cx, }
+}
diff --git a/crates/website/src/site/routes/servers/server_list.rs b/crates/website/src/site/routes/servers/server_list.rs
new file mode 100644
index 00000000..becebc68
--- /dev/null
+++ b/crates/website/src/site/routes/servers/server_list.rs
@@ -0,0 +1,18 @@
+use leptos::*;
+use leptos_router::*;
+
+use crate::site::components::NavBar;
+
+#[component]
+pub fn ServerList(cx: Scope) -> impl IntoView {
+ view! { cx,
+
+
+
+
+
+ Go to server
+
+
+ }
+}
diff --git a/crates/website/src/utils/icon.rs b/crates/website/src/utils/icon.rs
new file mode 100644
index 00000000..5c9e9c4a
--- /dev/null
+++ b/crates/website/src/utils/icon.rs
@@ -0,0 +1,6 @@
+#[macro_export]
+macro_rules! icon {
+ ($name: ident) => {
+ Icon::from(FaIcon::$name)
+ };
+}
diff --git a/crates/website/src/utils/mod.rs b/crates/website/src/utils/mod.rs
new file mode 100644
index 00000000..2bfe4707
--- /dev/null
+++ b/crates/website/src/utils/mod.rs
@@ -0,0 +1 @@
+mod icon;
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
index 30b6ff0e..a66b83a3 100644
--- a/crates/website/style/output.css
+++ b/crates/website/style/output.css
@@ -705,6 +705,11 @@ html {
}
}
+.link {
+ cursor: pointer;
+ text-decoration-line: underline;
+}
+
.navbar {
display: flex;
align-items: center;
@@ -858,6 +863,16 @@ html {
}
}
+.link:focus {
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+}
+
+.link:focus-visible {
+ outline: 2px solid currentColor;
+ outline-offset: 2px;
+}
+
@keyframes modal-pop {
0% {
opacity: 0;
From cf161d8c32437b653e7f9a78fc3fe99b78997bda Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Thu, 3 Aug 2023 21:56:22 -0400
Subject: [PATCH 015/119] add hero to Home
---
crates/website/src/site/routes/website/home.rs | 11 +++--------
crates/website/style/output.css | 17 +++++++++++++++++
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/crates/website/src/site/routes/website/home.rs b/crates/website/src/site/routes/website/home.rs
index 6f77d67a..89e54262 100644
--- a/crates/website/src/site/routes/website/home.rs
+++ b/crates/website/src/site/routes/website/home.rs
@@ -2,14 +2,9 @@ use leptos::*;
#[component]
pub fn Home(cx: Scope) -> impl IntoView {
- let (count, set_count) = create_signal(cx, 0);
- let on_click = move |_| set_count.update(|count| *count += 1);
-
view! { cx,
- "Welcome to Leptos!"
-
- "Click Me: "
- {count}
-
+
+ Hello 2!
+
}
}
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
index a66b83a3..863fc4c5 100644
--- a/crates/website/style/output.css
+++ b/crates/website/style/output.css
@@ -705,6 +705,19 @@ html {
}
}
+.hero {
+ display: grid;
+ width: 100%;
+ place-items: center;
+ background-size: cover;
+ background-position: center;
+}
+
+.hero > * {
+ grid-column-start: 1;
+ grid-row-start: 1;
+}
+
.link {
cursor: pointer;
text-decoration-line: underline;
@@ -1012,6 +1025,10 @@ html {
display: inline;
}
+.contents {
+ display: contents;
+}
+
.flex-1 {
flex: 1 1 0%;
}
From c47ecd76d7ad608c91097735caf24c2075b69e8c Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Fri, 4 Aug 2023 00:58:45 -0400
Subject: [PATCH 016/119] basic server-side get for website
---
Cargo.lock | 17 +++++++----
crates/common/Cargo.toml | 4 +++
.../src/client => common/src}/config.rs | 0
crates/common/src/lib.rs | 2 ++
crates/database/Cargo.toml | 2 +-
crates/database/src/models/guild.rs | 3 +-
crates/starboard/Cargo.toml | 3 +-
crates/starboard/src/client/bot.rs | 3 +-
crates/starboard/src/client/mod.rs | 1 -
crates/starboard/src/main.rs | 4 ++-
crates/website/Cargo.toml | 10 +++++++
crates/website/src/lib.rs | 5 ++++
crates/website/src/main.rs | 29 +++++++++++++++----
.../website/src/site/routes/servers/id/mod.rs | 16 ++++++++--
crates/website/style/output.css | 4 +++
15 files changed, 83 insertions(+), 20 deletions(-)
rename crates/{starboard/src/client => common/src}/config.rs (100%)
diff --git a/Cargo.lock b/Cargo.lock
index bed7e37d..7cace020 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -631,6 +631,9 @@ checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271"
[[package]]
name = "common"
version = "0.1.0"
+dependencies = [
+ "dotenv",
+]
[[package]]
name = "common_macros"
@@ -3235,9 +3238,9 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.180"
+version = "1.0.181"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed"
+checksum = "6d3e73c93c3240c0bda063c239298e633114c69a888c3e37ca8bb33f343e9890"
dependencies = [
"serde_derive",
]
@@ -3265,9 +3268,9 @@ dependencies = [
[[package]]
name = "serde_derive"
-version = "1.0.180"
+version = "1.0.181"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036"
+checksum = "be02f6cb0cd3a5ec20bbcfbcbd749f57daddb1a0882dc2e46a6c236c90b977ed"
dependencies = [
"proc-macro2",
"quote",
@@ -3640,7 +3643,6 @@ dependencies = [
"common",
"dashmap",
"database",
- "dotenv",
"emojis",
"errors",
"floodgate",
@@ -4443,13 +4445,18 @@ dependencies = [
"actix-files",
"actix-web",
"cfg-if",
+ "common",
"console_error_panic_hook",
+ "database",
+ "errors",
"http",
"leptos",
"leptos_actix",
"leptos_icons",
"leptos_meta",
"leptos_router",
+ "once_cell",
+ "serde",
"wasm-bindgen",
]
diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml
index e020b178..4f2e2fbb 100644
--- a/crates/common/Cargo.toml
+++ b/crates/common/Cargo.toml
@@ -4,3 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
+dotenv = { version = "0.15.0", optional = true }
+
+[features]
+backend = ["dep:dotenv"]
diff --git a/crates/starboard/src/client/config.rs b/crates/common/src/config.rs
similarity index 100%
rename from crates/starboard/src/client/config.rs
rename to crates/common/src/config.rs
diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs
index 0b6d2c4e..e514731c 100644
--- a/crates/common/src/lib.rs
+++ b/crates/common/src/lib.rs
@@ -1 +1,3 @@
+#[cfg(feature = "backend")]
+pub mod config;
pub mod constants;
diff --git a/crates/database/Cargo.toml b/crates/database/Cargo.toml
index dc07464f..595c4390 100644
--- a/crates/database/Cargo.toml
+++ b/crates/database/Cargo.toml
@@ -10,7 +10,7 @@ errors = {path = "../errors", optional = true}
serde_json = "1.0"
serde = "1.0.171"
serde_with = "3.0.0"
-chrono = "0.4.26"
+chrono = { version = "0.4.26", features = ["serde"] }
regex = "1.9.1"
sqlx = { version = "0.6.3", features = [
diff --git a/crates/database/src/models/guild.rs b/crates/database/src/models/guild.rs
index 9f0c660c..e4ad8b01 100644
--- a/crates/database/src/models/guild.rs
+++ b/crates/database/src/models/guild.rs
@@ -1,6 +1,7 @@
use chrono::{DateTime, Utc};
+use serde::{Deserialize, Serialize};
-#[derive(Debug)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DbGuild {
pub guild_id: i64,
pub premium_end: Option>,
diff --git a/crates/starboard/Cargo.toml b/crates/starboard/Cargo.toml
index 351783b4..3f33cc96 100644
--- a/crates/starboard/Cargo.toml
+++ b/crates/starboard/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
[dependencies]
database = {path = "../database", features = ["backend"]}
-common = {path = "../common"}
+common = {path = "../common", features = ["backend"]}
errors = {path = "../errors"}
twilight-gateway = "0.15.2"
@@ -21,7 +21,6 @@ twilight-interactions = "0.15.1"
async-trait = "0.1.71"
tokio = { version = "1.29.1", features = ["full"] }
futures = "0.3.28"
-dotenv = "0.15.0"
sqlx = { version = "0.6.3", features = ["macros", "postgres", "offline", "runtime-tokio-rustls", "chrono", "json"]}
chrono = "0.4.26"
serde_json = "1.0"
diff --git a/crates/starboard/src/client/bot.rs b/crates/starboard/src/client/bot.rs
index 8ccde916..4f27d7ec 100644
--- a/crates/starboard/src/client/bot.rs
+++ b/crates/starboard/src/client/bot.rs
@@ -13,9 +13,10 @@ use twilight_model::{
};
use twilight_standby::Standby;
+use common::config::Config;
use errors::{StarboardError, StarboardResult};
-use crate::{cache::Cache, client::config::Config, utils::into_id::IntoId};
+use crate::{cache::Cache, utils::into_id::IntoId};
use super::{cooldowns::Cooldowns, locks::Locks};
diff --git a/crates/starboard/src/client/mod.rs b/crates/starboard/src/client/mod.rs
index fa1c6c0c..6eb853ed 100644
--- a/crates/starboard/src/client/mod.rs
+++ b/crates/starboard/src/client/mod.rs
@@ -1,5 +1,4 @@
pub mod bot;
-pub mod config;
pub mod cooldowns;
pub mod locks;
pub mod runner;
diff --git a/crates/starboard/src/main.rs b/crates/starboard/src/main.rs
index eeafb5bc..23334697 100644
--- a/crates/starboard/src/main.rs
+++ b/crates/starboard/src/main.rs
@@ -10,7 +10,9 @@ pub mod utils;
use tokio::main;
-use crate::client::{bot::StarboardBot, config::Config, runner::run};
+use common::config::Config;
+
+use crate::client::{bot::StarboardBot, runner::run};
#[main]
async fn main() {
diff --git a/crates/website/Cargo.toml b/crates/website/Cargo.toml
index 09d2e31b..0225a669 100644
--- a/crates/website/Cargo.toml
+++ b/crates/website/Cargo.toml
@@ -7,6 +7,10 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dependencies]
+database = { path = "../database" }
+errors = { path = "../errors", optional = true }
+common = { path = "../common" }
+
actix-files = { version = "0.6", optional = true }
actix-web = { version = "4", optional = true, features = ["macros"] }
console_error_panic_hook = "0.1"
@@ -18,14 +22,20 @@ leptos_actix = { version = "0.4", optional = true }
leptos_router = { version = "0.4", features = ["nightly"] }
wasm-bindgen = "=0.2.87"
leptos_icons = { version = "0.0.15", features = ["FaChevronLeftSolid"] }
+serde = "1.0.181"
+once_cell = { version = "1.18.0", optional = true }
[features]
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
ssr = [
+ "database/backend",
+ "common/backend",
+ "dep:errors",
"dep:actix-files",
"dep:actix-web",
"dep:leptos_actix",
+ "dep:once_cell",
"leptos/ssr",
"leptos_meta/ssr",
"leptos_router/ssr",
diff --git a/crates/website/src/lib.rs b/crates/website/src/lib.rs
index e62fc3a6..5aa58cf3 100644
--- a/crates/website/src/lib.rs
+++ b/crates/website/src/lib.rs
@@ -2,6 +2,11 @@ pub mod app;
pub mod site;
pub mod utils;
+#[cfg(feature = "ssr")]
+pub fn db(cx: leptos::Scope) -> std::sync::Arc {
+ leptos::use_context::>(cx).expect("database")
+}
+
#[cfg(feature = "hydrate")]
use wasm_bindgen::prelude::wasm_bindgen;
diff --git a/crates/website/src/main.rs b/crates/website/src/main.rs
index fcfbafe1..a5974bbd 100644
--- a/crates/website/src/main.rs
+++ b/crates/website/src/main.rs
@@ -1,6 +1,8 @@
#[cfg(feature = "ssr")]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
+ use std::sync::Arc;
+
use actix_files::Files;
use actix_web::*;
use leptos::*;
@@ -12,23 +14,38 @@ async fn main() -> std::io::Result<()> {
// Generate the list of routes in your Leptos App
let routes = generate_route_list(|cx| view! { cx, });
+ let config = Arc::new(common::config::Config::from_env());
+ let db = Arc::new(database::DbClient::new(&config.db_url).await.unwrap());
+
HttpServer::new(move || {
let leptos_options = &conf.leptos_options;
let site_root = &leptos_options.site_root;
+ let db = db.clone();
+ let db2 = db.clone();
+ let config = config.clone();
+ let config2 = config.clone();
+
App::new()
- .route("/api/{tail:.*}", leptos_actix::handle_server_fns())
+ .route(
+ "/api/{tail:.*}",
+ leptos_actix::handle_server_fns_with_context(move |cx| {
+ provide_context(cx, db.clone());
+ provide_context(cx, config.clone());
+ }),
+ )
// serve JS/WASM/CSS from `pkg`
.service(Files::new("/pkg", format!("{site_root}/pkg")))
// serve other assets from the `assets` directory
.service(Files::new("/assets", site_root))
// serve the favicon from /favicon.ico
.service(favicon)
- .leptos_routes(
- leptos_options.to_owned(),
- routes.to_owned(),
- |cx| view! { cx, },
- )
+ .leptos_routes(leptos_options.to_owned(), routes.to_owned(), move |cx| {
+ provide_context(cx, db2.clone());
+ provide_context(cx, config2.clone());
+
+ view! { cx, }
+ })
.app_data(web::Data::new(leptos_options.to_owned()))
//.wrap(middleware::Compress::default())
})
diff --git a/crates/website/src/site/routes/servers/id/mod.rs b/crates/website/src/site/routes/servers/id/mod.rs
index d13a6039..bb176db2 100644
--- a/crates/website/src/site/routes/servers/id/mod.rs
+++ b/crates/website/src/site/routes/servers/id/mod.rs
@@ -2,6 +2,13 @@ use leptos::*;
use leptos_icons::*;
use leptos_router::*;
+#[server(GetGuild, "/api")]
+pub async fn get_guild(cx: Scope, id: i64) -> Result, ServerFnError> {
+ let db = crate::db(cx);
+
+ Ok(database::DbGuild::get(&db, id).await?)
+}
+
#[derive(Params, PartialEq)]
struct Props {
id: i64,
@@ -10,14 +17,19 @@ struct Props {
#[component]
pub fn Server(cx: Scope) -> impl IntoView {
let params = use_params::(cx);
-
let id = move || params.with(|p| p.as_ref().unwrap().id);
+ let guild = create_resource(cx, id, move |id| async move { get_guild(cx, id).await });
view! { cx,
- {id}
+
+ "Loading..."
}
+ }>{move || { guild.read(cx).map(|guild| view! { cx, {format!("{:?}", guild)} }) }}
+
+
}
}
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
index 863fc4c5..b4bd9da0 100644
--- a/crates/website/style/output.css
+++ b/crates/website/style/output.css
@@ -1021,6 +1021,10 @@ html {
border-bottom-right-radius: var(--rounded-btn, 0.5rem);
}
+.static {
+ position: static;
+}
+
.inline {
display: inline;
}
From 81ef52913e457a6d303da9f8b77f1c96d24e031e Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Fri, 4 Aug 2023 10:30:50 -0400
Subject: [PATCH 017/119] drop clone
---
crates/database/src/models/guild.rs | 2 +-
crates/website/src/site/routes/servers/id/mod.rs | 7 ++++---
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/crates/database/src/models/guild.rs b/crates/database/src/models/guild.rs
index e4ad8b01..1cf6507b 100644
--- a/crates/database/src/models/guild.rs
+++ b/crates/database/src/models/guild.rs
@@ -1,7 +1,7 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize)]
pub struct DbGuild {
pub guild_id: i64,
pub premium_end: Option>,
diff --git a/crates/website/src/site/routes/servers/id/mod.rs b/crates/website/src/site/routes/servers/id/mod.rs
index bb176db2..30864a17 100644
--- a/crates/website/src/site/routes/servers/id/mod.rs
+++ b/crates/website/src/site/routes/servers/id/mod.rs
@@ -18,7 +18,7 @@ struct Props {
pub fn Server(cx: Scope) -> impl IntoView {
let params = use_params::(cx);
let id = move || params.with(|p| p.as_ref().unwrap().id);
- let guild = create_resource(cx, id, move |id| async move { get_guild(cx, id).await });
+ let guild = create_resource(cx, id, move |id| get_guild(cx, id));
view! { cx,
@@ -27,7 +27,8 @@ pub fn Server(cx: Scope) -> impl IntoView {
"Loading..." }
- }>{move || { guild.read(cx).map(|guild| view! { cx, {format!("{:?}", guild)} }) }}
+ }>
+ {move || guild.with(cx, |g| format!("{g:?}")) }
}
@@ -40,7 +41,7 @@ fn ServerNavBar(cx: Scope) -> impl IntoView {
From 1ece009acdbc5ef64835ab9393c299be4eb89350 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Fri, 4 Aug 2023 12:43:27 -0400
Subject: [PATCH 018/119] add serde Serialize/Deserialize to all models
---
crates/database/src/models/autostar_channel.rs | 3 ++-
crates/database/src/models/autostar_channel_filter_group.rs | 3 +++
crates/database/src/models/exclusive_group.rs | 3 +++
crates/database/src/models/filter.rs | 2 ++
crates/database/src/models/filter_group.rs | 3 +++
crates/database/src/models/member.rs | 3 ++-
crates/database/src/models/message.rs | 4 +++-
crates/database/src/models/patron.rs | 4 +++-
crates/database/src/models/permrole.rs | 4 +++-
crates/database/src/models/permrole_starboard.rs | 4 +++-
crates/database/src/models/posrole.rs | 4 +++-
crates/database/src/models/starboard.rs | 4 +++-
crates/database/src/models/starboard_filter_group.rs | 3 +++
crates/database/src/models/starboard_message.rs | 4 +++-
crates/database/src/models/starboard_override.rs | 4 +++-
crates/database/src/models/starboard_settings.rs | 4 +++-
crates/database/src/models/user.rs | 4 +++-
crates/database/src/models/vote.rs | 4 +++-
crates/database/src/models/xprole.rs | 4 +++-
crates/website/src/site/routes/servers/id/overview.rs | 0
20 files changed, 54 insertions(+), 14 deletions(-)
create mode 100644 crates/website/src/site/routes/servers/id/overview.rs
diff --git a/crates/database/src/models/autostar_channel.rs b/crates/database/src/models/autostar_channel.rs
index d968e447..1c84548c 100644
--- a/crates/database/src/models/autostar_channel.rs
+++ b/crates/database/src/models/autostar_channel.rs
@@ -1,10 +1,11 @@
+use serde::{Deserialize, Serialize};
#[cfg(feature = "backend")]
use sqlx::FromRow;
#[cfg(feature = "backend")]
use crate::helpers::query::build_update::build_update;
-#[derive(Debug)]
+#[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "backend", derive(FromRow))]
pub struct AutoStarChannel {
/// serial
diff --git a/crates/database/src/models/autostar_channel_filter_group.rs b/crates/database/src/models/autostar_channel_filter_group.rs
index 6b556e21..8f239ae4 100644
--- a/crates/database/src/models/autostar_channel_filter_group.rs
+++ b/crates/database/src/models/autostar_channel_filter_group.rs
@@ -1,3 +1,6 @@
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct AutostarChannelFilterGroup {
pub filter_group_id: i32,
pub autostar_channel_id: i32,
diff --git a/crates/database/src/models/exclusive_group.rs b/crates/database/src/models/exclusive_group.rs
index a900333f..673e8afd 100644
--- a/crates/database/src/models/exclusive_group.rs
+++ b/crates/database/src/models/exclusive_group.rs
@@ -1,3 +1,6 @@
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct ExclusiveGroup {
pub id: i32,
pub guild_id: i64,
diff --git a/crates/database/src/models/filter.rs b/crates/database/src/models/filter.rs
index fd2de869..209672d9 100644
--- a/crates/database/src/models/filter.rs
+++ b/crates/database/src/models/filter.rs
@@ -1,9 +1,11 @@
+use serde::{Serialize, Deserialize};
#[cfg(feature = "backend")]
use sqlx::FromRow;
#[cfg(feature = "backend")]
use crate::helpers::query::build_update::build_update;
+#[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "backend", derive(FromRow))]
pub struct Filter {
pub id: i32,
diff --git a/crates/database/src/models/filter_group.rs b/crates/database/src/models/filter_group.rs
index 10bcd1a3..7f1ad13a 100644
--- a/crates/database/src/models/filter_group.rs
+++ b/crates/database/src/models/filter_group.rs
@@ -1,3 +1,6 @@
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct FilterGroup {
pub id: i32,
pub guild_id: i64,
diff --git a/crates/database/src/models/member.rs b/crates/database/src/models/member.rs
index b4f8ef1e..1d9cc9ed 100644
--- a/crates/database/src/models/member.rs
+++ b/crates/database/src/models/member.rs
@@ -1,7 +1,8 @@
#[cfg(feature = "backend")]
use futures::stream::BoxStream;
+use serde::{Deserialize, Serialize};
-#[derive(Debug)]
+#[derive(Debug, Serialize, Deserialize)]
pub struct DbMember {
pub user_id: i64,
pub guild_id: i64,
diff --git a/crates/database/src/models/message.rs b/crates/database/src/models/message.rs
index 9bd5b48a..b1c61f7d 100644
--- a/crates/database/src/models/message.rs
+++ b/crates/database/src/models/message.rs
@@ -1,4 +1,6 @@
-#[derive(Debug)]
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct DbMessage {
pub message_id: i64,
pub guild_id: i64,
diff --git a/crates/database/src/models/patron.rs b/crates/database/src/models/patron.rs
index 2f3ed770..0efb1f35 100644
--- a/crates/database/src/models/patron.rs
+++ b/crates/database/src/models/patron.rs
@@ -1,4 +1,6 @@
-#[derive(Debug)]
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct Patron {
pub patreon_id: String,
pub discord_id: Option,
diff --git a/crates/database/src/models/permrole.rs b/crates/database/src/models/permrole.rs
index dc6601b7..378cafaf 100644
--- a/crates/database/src/models/permrole.rs
+++ b/crates/database/src/models/permrole.rs
@@ -1,4 +1,6 @@
-#[derive(Debug)]
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct PermRole {
pub role_id: i64,
pub guild_id: i64,
diff --git a/crates/database/src/models/permrole_starboard.rs b/crates/database/src/models/permrole_starboard.rs
index 1ce9e3e1..97121a8d 100644
--- a/crates/database/src/models/permrole_starboard.rs
+++ b/crates/database/src/models/permrole_starboard.rs
@@ -1,4 +1,6 @@
-#[derive(Debug)]
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct PermRoleStarboard {
pub permrole_id: i64,
pub starboard_id: i32,
diff --git a/crates/database/src/models/posrole.rs b/crates/database/src/models/posrole.rs
index badd0fb9..8f2859eb 100644
--- a/crates/database/src/models/posrole.rs
+++ b/crates/database/src/models/posrole.rs
@@ -1,4 +1,6 @@
-#[derive(Debug)]
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct PosRole {
pub role_id: i64,
pub guild_id: i64,
diff --git a/crates/database/src/models/starboard.rs b/crates/database/src/models/starboard.rs
index 8c54bc01..1bf05497 100644
--- a/crates/database/src/models/starboard.rs
+++ b/crates/database/src/models/starboard.rs
@@ -1,10 +1,12 @@
+use serde::{Serialize, Deserialize};
+
#[cfg(feature = "backend")]
use crate::{
call_with_starboard_settings, helpers::query::build_update::build_update,
starboard_from_record, starboard_from_row, DbClient,
};
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Starboard {
pub id: i32,
pub name: String,
diff --git a/crates/database/src/models/starboard_filter_group.rs b/crates/database/src/models/starboard_filter_group.rs
index 2ceecf9e..31964838 100644
--- a/crates/database/src/models/starboard_filter_group.rs
+++ b/crates/database/src/models/starboard_filter_group.rs
@@ -1,3 +1,6 @@
+use serde::{Serialize, Deserialize};
+
+#[derive(Clone, Serialize, Deserialize)]
pub struct StarboardFilterGroup {
pub filter_group_id: i32,
pub starboard_id: i32,
diff --git a/crates/database/src/models/starboard_message.rs b/crates/database/src/models/starboard_message.rs
index 40396ef3..4fdade7f 100644
--- a/crates/database/src/models/starboard_message.rs
+++ b/crates/database/src/models/starboard_message.rs
@@ -1,4 +1,6 @@
-#[derive(Debug)]
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "backend", derive(sqlx::FromRow))]
pub struct StarboardMessage {
pub message_id: i64,
diff --git a/crates/database/src/models/starboard_override.rs b/crates/database/src/models/starboard_override.rs
index df6c5176..e915c079 100644
--- a/crates/database/src/models/starboard_override.rs
+++ b/crates/database/src/models/starboard_override.rs
@@ -1,4 +1,6 @@
-#[derive(Debug)]
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct StarboardOverride {
// serial
pub id: i32,
diff --git a/crates/database/src/models/starboard_settings.rs b/crates/database/src/models/starboard_settings.rs
index d4b8263f..0bd146f6 100644
--- a/crates/database/src/models/starboard_settings.rs
+++ b/crates/database/src/models/starboard_settings.rs
@@ -1,4 +1,6 @@
-#[derive(Clone, Debug)]
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StarboardSettings {
// General Style
pub display_emoji: Option,
diff --git a/crates/database/src/models/user.rs b/crates/database/src/models/user.rs
index 8d810bdf..7c4807dd 100644
--- a/crates/database/src/models/user.rs
+++ b/crates/database/src/models/user.rs
@@ -1,4 +1,6 @@
-#[derive(Debug)]
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct DbUser {
pub user_id: i64,
pub is_bot: bool,
diff --git a/crates/database/src/models/vote.rs b/crates/database/src/models/vote.rs
index 6bc8993a..33ecdba2 100644
--- a/crates/database/src/models/vote.rs
+++ b/crates/database/src/models/vote.rs
@@ -1,4 +1,6 @@
-#[derive(Debug)]
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct Vote {
pub message_id: i64,
pub starboard_id: i32,
diff --git a/crates/database/src/models/xprole.rs b/crates/database/src/models/xprole.rs
index a07898b8..a5b6160a 100644
--- a/crates/database/src/models/xprole.rs
+++ b/crates/database/src/models/xprole.rs
@@ -1,4 +1,6 @@
-#[derive(Debug)]
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Serialize, Deserialize)]
pub struct XPRole {
pub role_id: i64,
pub guild_id: i64,
diff --git a/crates/website/src/site/routes/servers/id/overview.rs b/crates/website/src/site/routes/servers/id/overview.rs
new file mode 100644
index 00000000..e69de29b
From 3885bbc31e80c7f159117fcd58d86f5abdefab51 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Fri, 4 Aug 2023 18:15:06 -0400
Subject: [PATCH 019/119] progress
---
.vscode/settings.json | 6 +-
Cargo.lock | 2 +
.../database/src/models/autostar_channel.rs | 2 +-
.../models/autostar_channel_filter_group.rs | 4 +-
crates/database/src/models/exclusive_group.rs | 4 +-
crates/database/src/models/filter.rs | 4 +-
crates/database/src/models/filter_group.rs | 4 +-
crates/database/src/models/guild.rs | 2 +-
crates/database/src/models/member.rs | 2 +-
crates/database/src/models/message.rs | 4 +-
crates/database/src/models/patron.rs | 2 +-
crates/database/src/models/permrole.rs | 4 +-
.../database/src/models/permrole_starboard.rs | 4 +-
crates/database/src/models/posrole.rs | 4 +-
crates/database/src/models/starboard.rs | 2 +-
.../src/models/starboard_filter_group.rs | 4 +-
.../database/src/models/starboard_message.rs | 4 +-
.../database/src/models/starboard_override.rs | 4 +-
.../src/models/starboard_override_values.rs | 2 +-
.../database/src/models/starboard_settings.rs | 2 +-
crates/database/src/models/user.rs | 4 +-
crates/database/src/models/vote.rs | 4 +-
crates/database/src/models/xprole.rs | 4 +-
crates/website/Cargo.toml | 3 +
crates/website/src/lib.rs | 7 +-
crates/website/src/main.rs | 14 +++-
crates/website/src/site/routes/mod.rs | 7 +-
.../website/src/site/routes/servers/id/mod.rs | 77 ++++++++++++++++---
.../src/site/routes/servers/id/overview.rs | 12 +++
crates/website/style/output.css | 8 --
30 files changed, 143 insertions(+), 63 deletions(-)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index fcfafe58..76d64cdb 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -16,9 +16,9 @@
"strings": true
},
"css.validate": false,
- "rust-analyzer.procMacro.ignored": {
- "leptos_macro": ["server", "component"]
- },
+ // "rust-analyzer.procMacro.ignored": {
+ // "leptos_macro": ["server", "component"]
+ // },
"rust-analyzer.check.command": "clippy",
"rust-analyzer.showUnlinkedFileNotification": false
}
diff --git a/Cargo.lock b/Cargo.lock
index 7cace020..6a340f62 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4457,6 +4457,8 @@ dependencies = [
"leptos_router",
"once_cell",
"serde",
+ "twilight-http",
+ "twilight-model",
"wasm-bindgen",
]
diff --git a/crates/database/src/models/autostar_channel.rs b/crates/database/src/models/autostar_channel.rs
index 1c84548c..6305bd28 100644
--- a/crates/database/src/models/autostar_channel.rs
+++ b/crates/database/src/models/autostar_channel.rs
@@ -5,7 +5,7 @@ use sqlx::FromRow;
#[cfg(feature = "backend")]
use crate::helpers::query::build_update::build_update;
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "backend", derive(FromRow))]
pub struct AutoStarChannel {
/// serial
diff --git a/crates/database/src/models/autostar_channel_filter_group.rs b/crates/database/src/models/autostar_channel_filter_group.rs
index 8f239ae4..08dedd94 100644
--- a/crates/database/src/models/autostar_channel_filter_group.rs
+++ b/crates/database/src/models/autostar_channel_filter_group.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AutostarChannelFilterGroup {
pub filter_group_id: i32,
pub autostar_channel_id: i32,
diff --git a/crates/database/src/models/exclusive_group.rs b/crates/database/src/models/exclusive_group.rs
index 673e8afd..4909722b 100644
--- a/crates/database/src/models/exclusive_group.rs
+++ b/crates/database/src/models/exclusive_group.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExclusiveGroup {
pub id: i32,
pub guild_id: i64,
diff --git a/crates/database/src/models/filter.rs b/crates/database/src/models/filter.rs
index 209672d9..01ae7818 100644
--- a/crates/database/src/models/filter.rs
+++ b/crates/database/src/models/filter.rs
@@ -1,11 +1,11 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
#[cfg(feature = "backend")]
use sqlx::FromRow;
#[cfg(feature = "backend")]
use crate::helpers::query::build_update::build_update;
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "backend", derive(FromRow))]
pub struct Filter {
pub id: i32,
diff --git a/crates/database/src/models/filter_group.rs b/crates/database/src/models/filter_group.rs
index 7f1ad13a..d09fb444 100644
--- a/crates/database/src/models/filter_group.rs
+++ b/crates/database/src/models/filter_group.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FilterGroup {
pub id: i32,
pub guild_id: i64,
diff --git a/crates/database/src/models/guild.rs b/crates/database/src/models/guild.rs
index 1cf6507b..e4ad8b01 100644
--- a/crates/database/src/models/guild.rs
+++ b/crates/database/src/models/guild.rs
@@ -1,7 +1,7 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DbGuild {
pub guild_id: i64,
pub premium_end: Option>,
diff --git a/crates/database/src/models/member.rs b/crates/database/src/models/member.rs
index 1d9cc9ed..75730822 100644
--- a/crates/database/src/models/member.rs
+++ b/crates/database/src/models/member.rs
@@ -2,7 +2,7 @@
use futures::stream::BoxStream;
use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DbMember {
pub user_id: i64,
pub guild_id: i64,
diff --git a/crates/database/src/models/message.rs b/crates/database/src/models/message.rs
index b1c61f7d..0daf19e4 100644
--- a/crates/database/src/models/message.rs
+++ b/crates/database/src/models/message.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DbMessage {
pub message_id: i64,
pub guild_id: i64,
diff --git a/crates/database/src/models/patron.rs b/crates/database/src/models/patron.rs
index 0efb1f35..4f40bae3 100644
--- a/crates/database/src/models/patron.rs
+++ b/crates/database/src/models/patron.rs
@@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Patron {
pub patreon_id: String,
pub discord_id: Option,
diff --git a/crates/database/src/models/permrole.rs b/crates/database/src/models/permrole.rs
index 378cafaf..d18d9538 100644
--- a/crates/database/src/models/permrole.rs
+++ b/crates/database/src/models/permrole.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PermRole {
pub role_id: i64,
pub guild_id: i64,
diff --git a/crates/database/src/models/permrole_starboard.rs b/crates/database/src/models/permrole_starboard.rs
index 97121a8d..6b6f04eb 100644
--- a/crates/database/src/models/permrole_starboard.rs
+++ b/crates/database/src/models/permrole_starboard.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PermRoleStarboard {
pub permrole_id: i64,
pub starboard_id: i32,
diff --git a/crates/database/src/models/posrole.rs b/crates/database/src/models/posrole.rs
index 8f2859eb..ac3f99e6 100644
--- a/crates/database/src/models/posrole.rs
+++ b/crates/database/src/models/posrole.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PosRole {
pub role_id: i64,
pub guild_id: i64,
diff --git a/crates/database/src/models/starboard.rs b/crates/database/src/models/starboard.rs
index 1bf05497..6befeb15 100644
--- a/crates/database/src/models/starboard.rs
+++ b/crates/database/src/models/starboard.rs
@@ -1,4 +1,4 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
#[cfg(feature = "backend")]
use crate::{
diff --git a/crates/database/src/models/starboard_filter_group.rs b/crates/database/src/models/starboard_filter_group.rs
index 31964838..4fcbcd84 100644
--- a/crates/database/src/models/starboard_filter_group.rs
+++ b/crates/database/src/models/starboard_filter_group.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StarboardFilterGroup {
pub filter_group_id: i32,
pub starboard_id: i32,
diff --git a/crates/database/src/models/starboard_message.rs b/crates/database/src/models/starboard_message.rs
index 4fdade7f..0e11b3aa 100644
--- a/crates/database/src/models/starboard_message.rs
+++ b/crates/database/src/models/starboard_message.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "backend", derive(sqlx::FromRow))]
pub struct StarboardMessage {
pub message_id: i64,
diff --git a/crates/database/src/models/starboard_override.rs b/crates/database/src/models/starboard_override.rs
index e915c079..798090f5 100644
--- a/crates/database/src/models/starboard_override.rs
+++ b/crates/database/src/models/starboard_override.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StarboardOverride {
// serial
pub id: i32,
diff --git a/crates/database/src/models/starboard_override_values.rs b/crates/database/src/models/starboard_override_values.rs
index 5320e8c3..aa88bc14 100644
--- a/crates/database/src/models/starboard_override_values.rs
+++ b/crates/database/src/models/starboard_override_values.rs
@@ -12,7 +12,7 @@ where
}
#[skip_serializing_none]
-#[derive(Debug, Serialize, Deserialize, Default)]
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct OverrideValues {
// General Style
#[serde(deserialize_with = "null_to_some_none", default)]
diff --git a/crates/database/src/models/starboard_settings.rs b/crates/database/src/models/starboard_settings.rs
index 0bd146f6..5385cce9 100644
--- a/crates/database/src/models/starboard_settings.rs
+++ b/crates/database/src/models/starboard_settings.rs
@@ -1,4 +1,4 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StarboardSettings {
diff --git a/crates/database/src/models/user.rs b/crates/database/src/models/user.rs
index 7c4807dd..07b54e9e 100644
--- a/crates/database/src/models/user.rs
+++ b/crates/database/src/models/user.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DbUser {
pub user_id: i64,
pub is_bot: bool,
diff --git a/crates/database/src/models/vote.rs b/crates/database/src/models/vote.rs
index 33ecdba2..03b9c05a 100644
--- a/crates/database/src/models/vote.rs
+++ b/crates/database/src/models/vote.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Vote {
pub message_id: i64,
pub starboard_id: i32,
diff --git a/crates/database/src/models/xprole.rs b/crates/database/src/models/xprole.rs
index a5b6160a..f240e668 100644
--- a/crates/database/src/models/xprole.rs
+++ b/crates/database/src/models/xprole.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct XPRole {
pub role_id: i64,
pub guild_id: i64,
diff --git a/crates/website/Cargo.toml b/crates/website/Cargo.toml
index 0225a669..fd65dfbe 100644
--- a/crates/website/Cargo.toml
+++ b/crates/website/Cargo.toml
@@ -24,6 +24,8 @@ wasm-bindgen = "=0.2.87"
leptos_icons = { version = "0.0.15", features = ["FaChevronLeftSolid"] }
serde = "1.0.181"
once_cell = { version = "1.18.0", optional = true }
+twilight-model = "0.15.2"
+twilight-http = { version = "0.15.2", optional = true }
[features]
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
@@ -36,6 +38,7 @@ ssr = [
"dep:actix-web",
"dep:leptos_actix",
"dep:once_cell",
+ "dep:twilight-http",
"leptos/ssr",
"leptos_meta/ssr",
"leptos_router/ssr",
diff --git a/crates/website/src/lib.rs b/crates/website/src/lib.rs
index 5aa58cf3..7908413e 100644
--- a/crates/website/src/lib.rs
+++ b/crates/website/src/lib.rs
@@ -4,7 +4,12 @@ pub mod utils;
#[cfg(feature = "ssr")]
pub fn db(cx: leptos::Scope) -> std::sync::Arc {
- leptos::use_context::>(cx).expect("database")
+ leptos::use_context(cx).expect("database")
+}
+
+#[cfg(feature = "ssr")]
+pub fn http(cx: leptos::Scope) -> std::sync::Arc {
+ leptos::use_context(cx).expect("http client")
}
#[cfg(feature = "hydrate")]
diff --git a/crates/website/src/main.rs b/crates/website/src/main.rs
index a5974bbd..bfe2f8ad 100644
--- a/crates/website/src/main.rs
+++ b/crates/website/src/main.rs
@@ -1,12 +1,13 @@
#[cfg(feature = "ssr")]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
- use std::sync::Arc;
+ use std::{sync::Arc, time::Duration};
use actix_files::Files;
use actix_web::*;
use leptos::*;
use leptos_actix::{generate_route_list, LeptosRoutes};
+ use twilight_http::client::Client as HttpClient;
use website::app::*;
let conf = get_configuration(None).await.unwrap();
@@ -16,6 +17,13 @@ async fn main() -> std::io::Result<()> {
let config = Arc::new(common::config::Config::from_env());
let db = Arc::new(database::DbClient::new(&config.db_url).await.unwrap());
+ let mut http = HttpClient::builder()
+ .token(config.token.clone())
+ .timeout(Duration::from_secs(30));
+ if let Some(proxy) = &config.proxy {
+ http = http.proxy(proxy.to_owned(), true);
+ }
+ let http = Arc::new(http.build());
HttpServer::new(move || {
let leptos_options = &conf.leptos_options;
@@ -25,6 +33,8 @@ async fn main() -> std::io::Result<()> {
let db2 = db.clone();
let config = config.clone();
let config2 = config.clone();
+ let http = http.clone();
+ let http2 = http.clone();
App::new()
.route(
@@ -32,6 +42,7 @@ async fn main() -> std::io::Result<()> {
leptos_actix::handle_server_fns_with_context(move |cx| {
provide_context(cx, db.clone());
provide_context(cx, config.clone());
+ provide_context(cx, http.clone());
}),
)
// serve JS/WASM/CSS from `pkg`
@@ -43,6 +54,7 @@ async fn main() -> std::io::Result<()> {
.leptos_routes(leptos_options.to_owned(), routes.to_owned(), move |cx| {
provide_context(cx, db2.clone());
provide_context(cx, config2.clone());
+ provide_context(cx, http2.clone());
view! { cx, }
})
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index 88fdf047..de76bb49 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -34,13 +34,12 @@ fn DashboardRoutes(cx: Scope) -> impl IntoView {
view! { cx,
-
- //
+
+
//
//
//
-
- //
+
diff --git a/crates/website/src/site/routes/servers/id/mod.rs b/crates/website/src/site/routes/servers/id/mod.rs
index 30864a17..42d17b27 100644
--- a/crates/website/src/site/routes/servers/id/mod.rs
+++ b/crates/website/src/site/routes/servers/id/mod.rs
@@ -1,47 +1,102 @@
+pub mod overview;
+
+use database::DbGuild;
use leptos::*;
use leptos_icons::*;
use leptos_router::*;
+use serde::{Deserialize, Serialize};
+use twilight_model::guild::Guild;
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct GuildData {
+ pub db: DbGuild,
+ pub http: Guild,
+}
+
+pub type GuildContext = Resource>;
#[server(GetGuild, "/api")]
-pub async fn get_guild(cx: Scope, id: i64) -> Result, ServerFnError> {
+pub async fn get_guild(cx: Scope, id: u64) -> Result , ServerFnError> {
+ use twilight_model::id::Id;
+
let db = crate::db(cx);
+ let http = crate::http(cx);
+
+ let http_guild = match http.guild(Id::new(id)).await {
+ Ok(res) => res.model().await?,
+ Err(why) => {
+ if errors::get_status(&why) == Some(404) {
+ return Ok(None);
+ } else {
+ return Err(why.into());
+ }
+ }
+ };
+ let db_guild = match DbGuild::create(&db, id as i64).await? {
+ Some(v) => v,
+ None => DbGuild::get(&db, id as i64)
+ .await?
+ .expect("guild wasn't deleted"),
+ };
- Ok(database::DbGuild::get(&db, id).await?)
+ Ok(Some(GuildData {
+ db: db_guild,
+ http: http_guild,
+ }))
}
#[derive(Params, PartialEq)]
struct Props {
- id: i64,
+ id: u64,
}
#[component]
pub fn Server(cx: Scope) -> impl IntoView {
let params = use_params::(cx);
let id = move || params.with(|p| p.as_ref().unwrap().id);
- let guild = create_resource(cx, id, move |id| get_guild(cx, id));
+ let guild = create_resource(cx, id, move |id| async move {
+ get_guild(cx, id).await.ok().flatten()
+ });
+ provide_context(cx, guild);
view! { cx,
+
+ {move || {
+ guild
+ .with(
+ cx,
+ |g| {
+ if !g.is_some() {
+ Some(
+ Redirect(cx, RedirectProps::builder().path("/servers").build()),
+ )
+ } else {
+ None
+ }
+ },
+ )
+ }}
+
+
- "Loading..." }
- }>
- {move || guild.with(cx, |g| format!("{g:?}")) }
-
+
}
}
#[component]
fn ServerNavBar(cx: Scope) -> impl IntoView {
+ let guild = expect_context::(cx);
+
view! { cx,
diff --git a/crates/website/src/site/routes/servers/id/overview.rs b/crates/website/src/site/routes/servers/id/overview.rs
index e69de29b..8f4cf9e0 100644
--- a/crates/website/src/site/routes/servers/id/overview.rs
+++ b/crates/website/src/site/routes/servers/id/overview.rs
@@ -0,0 +1,12 @@
+use leptos::*;
+
+#[component]
+pub fn Overview(cx: Scope) -> impl IntoView {
+ let guild = expect_context::(cx);
+
+ view! { cx,
+ {move || format!("{:?}", dbg!(guild.read(cx)))}
+ }
+}
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
index b4bd9da0..adaa9205 100644
--- a/crates/website/style/output.css
+++ b/crates/website/style/output.css
@@ -1021,18 +1021,10 @@ html {
border-bottom-right-radius: var(--rounded-btn, 0.5rem);
}
-.static {
- position: static;
-}
-
.inline {
display: inline;
}
-.contents {
- display: contents;
-}
-
.flex-1 {
flex: 1 1 0%;
}
From dfca1c4b45551b6936f0ccdff1854292c7b99ad8 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Fri, 4 Aug 2023 18:19:35 -0400
Subject: [PATCH 020/119] better formatting
---
.../website/src/site/routes/servers/id/mod.rs | 35 +++++++++----------
.../src/site/routes/servers/id/overview.rs | 7 ++--
.../src/site/routes/servers/server_list.rs | 2 +-
3 files changed, 19 insertions(+), 25 deletions(-)
diff --git a/crates/website/src/site/routes/servers/id/mod.rs b/crates/website/src/site/routes/servers/id/mod.rs
index 42d17b27..9b22773d 100644
--- a/crates/website/src/site/routes/servers/id/mod.rs
+++ b/crates/website/src/site/routes/servers/id/mod.rs
@@ -59,25 +59,21 @@ pub fn Server(cx: Scope) -> impl IntoView {
});
provide_context(cx, guild);
- view! { cx,
-
- {move || {
- guild
- .with(
- cx,
- |g| {
- if !g.is_some() {
- Some(
- Redirect(cx, RedirectProps::builder().path("/servers").build()),
- )
- } else {
- None
- }
- },
- )
- }}
+ let red = move || {
+ guild.with(cx, |g| {
+ if !g.is_some() {
+ Some(Redirect(
+ cx,
+ RedirectProps::builder().path("/servers").build(),
+ ))
+ } else {
+ None
+ }
+ })
+ };
-
+ view! { cx,
+ {red}
@@ -91,12 +87,13 @@ pub fn Server(cx: Scope) -> impl IntoView {
fn ServerNavBar(cx: Scope) -> impl IntoView {
let guild = expect_context::(cx);
+ let title = move || guild.with(cx, |g| g.as_ref().map(|g| g.http.name.to_owned()));
view! { cx,
diff --git a/crates/website/src/site/routes/servers/id/overview.rs b/crates/website/src/site/routes/servers/id/overview.rs
index 8f4cf9e0..d0051cbd 100644
--- a/crates/website/src/site/routes/servers/id/overview.rs
+++ b/crates/website/src/site/routes/servers/id/overview.rs
@@ -4,9 +4,6 @@ use leptos::*;
pub fn Overview(cx: Scope) -> impl IntoView {
let guild = expect_context::(cx);
- view! { cx,
- {move || format!("{:?}", dbg!(guild.read(cx)))}
- }
+ let content = move || format!("{:?}", guild.read(cx));
+ view! { cx, {content} }
}
diff --git a/crates/website/src/site/routes/servers/server_list.rs b/crates/website/src/site/routes/servers/server_list.rs
index becebc68..ea72ca0d 100644
--- a/crates/website/src/site/routes/servers/server_list.rs
+++ b/crates/website/src/site/routes/servers/server_list.rs
@@ -11,7 +11,7 @@ pub fn ServerList(cx: Scope) -> impl IntoView {
- Go to server
+ "Go to server"
}
From 5c5fb03614a55954893e9a10e1dedd69286191c9 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Fri, 4 Aug 2023 19:06:38 -0400
Subject: [PATCH 021/119] Update settings.json
---
.vscode/settings.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 76d64cdb..fcfafe58 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -16,9 +16,9 @@
"strings": true
},
"css.validate": false,
- // "rust-analyzer.procMacro.ignored": {
- // "leptos_macro": ["server", "component"]
- // },
+ "rust-analyzer.procMacro.ignored": {
+ "leptos_macro": ["server", "component"]
+ },
"rust-analyzer.check.command": "clippy",
"rust-analyzer.showUnlinkedFileNotification": false
}
From e82543945c38f208edf4f55fa14ef4f91451211e Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Fri, 4 Aug 2023 19:10:29 -0400
Subject: [PATCH 022/119] Update settings.json
---
.vscode/settings.json | 3 ---
1 file changed, 3 deletions(-)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index fcfafe58..7bd004af 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -16,9 +16,6 @@
"strings": true
},
"css.validate": false,
- "rust-analyzer.procMacro.ignored": {
- "leptos_macro": ["server", "component"]
- },
"rust-analyzer.check.command": "clippy",
"rust-analyzer.showUnlinkedFileNotification": false
}
From c9a18a263346f123e6aafd15c908b227b08d055e Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Sat, 5 Aug 2023 18:49:13 -0400
Subject: [PATCH 023/119] working discord oauth2
---
.env.example | 2 +
Cargo.lock | 523 +++++++++++++++++-
crates/common/src/config.rs | 21 +-
crates/website/Cargo.toml | 5 +
crates/website/src/auth/context.rs | 43 ++
crates/website/src/auth/jwt.rs | 45 ++
crates/website/src/auth/mod.rs | 5 +
crates/website/src/auth/oauth2.rs | 87 +++
crates/website/src/lib.rs | 31 +-
crates/website/src/main.rs | 35 +-
crates/website/src/site/routes/auth/login.rs | 43 ++
crates/website/src/site/routes/auth/mod.rs | 2 +
.../website/src/site/routes/auth/redirect.rs | 32 ++
crates/website/src/site/routes/mod.rs | 24 +
.../website/src/site/routes/servers/id/mod.rs | 9 +-
crates/website/src/site/routes/servers/mod.rs | 25 +-
16 files changed, 906 insertions(+), 26 deletions(-)
create mode 100644 crates/website/src/auth/context.rs
create mode 100644 crates/website/src/auth/jwt.rs
create mode 100644 crates/website/src/auth/mod.rs
create mode 100644 crates/website/src/auth/oauth2.rs
create mode 100644 crates/website/src/site/routes/auth/login.rs
create mode 100644 crates/website/src/site/routes/auth/mod.rs
create mode 100644 crates/website/src/site/routes/auth/redirect.rs
diff --git a/.env.example b/.env.example
index 17686c51..1d5f1ad7 100644
--- a/.env.example
+++ b/.env.example
@@ -11,6 +11,8 @@
### bot config ###
##################
DISCORD_TOKEN=""
+CLIENT_SECRET=
+REDIRECT_URL=
BOT_ID=""
SHARDS=1
# true disables notifications
diff --git a/Cargo.lock b/Cargo.lock
index 6a340f62..31e95004 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -410,6 +410,12 @@ dependencies = [
"rustc-demangle",
]
+[[package]]
+name = "base16ct"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
+
[[package]]
name = "base64"
version = "0.13.1"
@@ -422,6 +428,18 @@ version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
+[[package]]
+name = "base64ct"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
+
+[[package]]
+name = "binstring"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e0d60973d9320722cb1206f412740e162a33b8547ea8d6be75d7cff237c7a85"
+
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -622,6 +640,18 @@ dependencies = [
"half",
]
+[[package]]
+name = "coarsetime"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a90d114103adbc625300f346d4d09dfb4ab1c4a8df6868435dd903392ecf4354"
+dependencies = [
+ "libc",
+ "once_cell",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
+]
+
[[package]]
name = "collection_literals"
version = "1.0.1"
@@ -679,6 +709,12 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "const-oid"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747"
+
[[package]]
name = "const_format"
version = "0.2.31"
@@ -816,6 +852,18 @@ dependencies = [
"cfg-if",
]
+[[package]]
+name = "crypto-bigint"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15"
+dependencies = [
+ "generic-array",
+ "rand_core",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "crypto-common"
version = "0.1.6"
@@ -826,6 +874,12 @@ dependencies = [
"typenum",
]
+[[package]]
+name = "ct-codecs"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df"
+
[[package]]
name = "darling"
version = "0.14.4"
@@ -956,6 +1010,28 @@ dependencies = [
"uuid",
]
+[[package]]
+name = "der"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
+dependencies = [
+ "const-oid",
+ "pem-rfc7468 0.6.0",
+ "zeroize",
+]
+
+[[package]]
+name = "der"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946"
+dependencies = [
+ "const-oid",
+ "pem-rfc7468 0.7.0",
+ "zeroize",
+]
+
[[package]]
name = "deranged"
version = "0.3.6"
@@ -996,6 +1072,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
+ "const-oid",
"crypto-common",
"subtle",
]
@@ -1050,6 +1127,30 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408"
+[[package]]
+name = "ecdsa"
+version = "0.16.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4"
+dependencies = [
+ "der 0.7.7",
+ "digest",
+ "elliptic-curve",
+ "rfc6979",
+ "signature 2.1.0",
+ "spki 0.7.2",
+]
+
+[[package]]
+name = "ed25519-compact"
+version = "2.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a3d382e8464107391c8706b4c14b087808ecb909f6c15c34114bc42e53a9e4c"
+dependencies = [
+ "ct-codecs",
+ "getrandom",
+]
+
[[package]]
name = "educe"
version = "0.4.22"
@@ -1071,6 +1172,27 @@ dependencies = [
"serde",
]
+[[package]]
+name = "elliptic-curve"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b"
+dependencies = [
+ "base16ct",
+ "crypto-bigint",
+ "digest",
+ "ff",
+ "generic-array",
+ "group",
+ "hkdf",
+ "pem-rfc7468 0.7.0",
+ "pkcs8 0.10.2",
+ "rand_core",
+ "sec1",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "emojis"
version = "0.6.0"
@@ -1175,6 +1297,16 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
+[[package]]
+name = "ff"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
+dependencies = [
+ "rand_core",
+ "subtle",
+]
+
[[package]]
name = "findshlibs"
version = "0.10.2"
@@ -1360,6 +1492,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
+ "zeroize",
]
[[package]]
@@ -1420,6 +1553,17 @@ dependencies = [
"web-sys",
]
+[[package]]
+name = "group"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
+dependencies = [
+ "ff",
+ "rand_core",
+ "subtle",
+]
+
[[package]]
name = "h2"
version = "0.3.20"
@@ -1521,6 +1665,30 @@ dependencies = [
"digest",
]
+[[package]]
+name = "hmac-sha1-compact"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dff9d405ec732fa3fcde87264e54a32a84956a377b3e3107de96e59b798c84a7"
+
+[[package]]
+name = "hmac-sha256"
+version = "1.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3688e69b38018fec1557254f64c8dc2cc8ec502890182f395dbb0aa997aa5735"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "hmac-sha512"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4ce1f4656bae589a3fab938f9f09bf58645b7ed01a2c5f8a3c238e01a4ef78a"
+dependencies = [
+ "digest",
+]
+
[[package]]
name = "hostname"
version = "0.3.1"
@@ -1619,10 +1787,24 @@ checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c"
dependencies = [
"http",
"hyper",
- "rustls",
+ "rustls 0.20.8",
"rustls-native-certs",
"tokio",
- "tokio-rustls",
+ "tokio-rustls 0.23.4",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97"
+dependencies = [
+ "futures-util",
+ "http",
+ "hyper",
+ "rustls 0.21.6",
+ "tokio",
+ "tokio-rustls 0.24.1",
]
[[package]]
@@ -1805,6 +1987,46 @@ dependencies = [
"serde",
]
+[[package]]
+name = "jwt-simple"
+version = "0.11.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "733741e7bcd1532b56c9ba6c698c069f274f3782ad956f0d2c7f31650cedaa1b"
+dependencies = [
+ "anyhow",
+ "binstring",
+ "coarsetime",
+ "ct-codecs",
+ "ed25519-compact",
+ "hmac-sha1-compact",
+ "hmac-sha256",
+ "hmac-sha512",
+ "k256",
+ "p256",
+ "p384",
+ "rand",
+ "rsa",
+ "serde",
+ "serde_json",
+ "spki 0.6.0",
+ "thiserror",
+ "zeroize",
+]
+
+[[package]]
+name = "k256"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc"
+dependencies = [
+ "cfg-if",
+ "ecdsa",
+ "elliptic-curve",
+ "once_cell",
+ "sha2",
+ "signature 2.1.0",
+]
+
[[package]]
name = "language-tags"
version = "0.3.2"
@@ -1816,6 +2038,9 @@ name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+dependencies = [
+ "spin",
+]
[[package]]
name = "leptos"
@@ -2053,6 +2278,12 @@ version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+[[package]]
+name = "libm"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
+
[[package]]
name = "libz-sys"
version = "1.1.12"
@@ -2312,6 +2543,23 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "num-bigint-dig"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
+dependencies = [
+ "byteorder",
+ "lazy_static",
+ "libm",
+ "num-integer",
+ "num-iter",
+ "num-traits",
+ "rand",
+ "smallvec",
+ "zeroize",
+]
+
[[package]]
name = "num-integer"
version = "0.1.45"
@@ -2322,6 +2570,17 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "num-iter"
+version = "0.1.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
[[package]]
name = "num-traits"
version = "0.2.16"
@@ -2329,6 +2588,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg",
+ "libm",
]
[[package]]
@@ -2341,6 +2601,26 @@ dependencies = [
"libc",
]
+[[package]]
+name = "oauth2"
+version = "4.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09a6e2a2b13a56ebeabba9142f911745be6456163fd6c3d361274ebcd891a80c"
+dependencies = [
+ "base64 0.13.1",
+ "chrono",
+ "getrandom",
+ "http",
+ "rand",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "serde_path_to_error",
+ "sha2",
+ "thiserror",
+ "url",
+]
+
[[package]]
name = "object"
version = "0.31.1"
@@ -2430,6 +2710,30 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "p256"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
+dependencies = [
+ "ecdsa",
+ "elliptic-curve",
+ "primeorder",
+ "sha2",
+]
+
+[[package]]
+name = "p384"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209"
+dependencies = [
+ "ecdsa",
+ "elliptic-curve",
+ "primeorder",
+ "sha2",
+]
+
[[package]]
name = "pad-adapter"
version = "0.1.1"
@@ -2502,6 +2806,24 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+[[package]]
+name = "pem-rfc7468"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac"
+dependencies = [
+ "base64ct",
+]
+
+[[package]]
+name = "pem-rfc7468"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
+dependencies = [
+ "base64ct",
+]
+
[[package]]
name = "percent-encoding"
version = "2.3.0"
@@ -2602,6 +2924,38 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+[[package]]
+name = "pkcs1"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719"
+dependencies = [
+ "der 0.6.1",
+ "pkcs8 0.9.0",
+ "spki 0.6.0",
+ "zeroize",
+]
+
+[[package]]
+name = "pkcs8"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
+dependencies = [
+ "der 0.6.1",
+ "spki 0.6.0",
+]
+
+[[package]]
+name = "pkcs8"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+dependencies = [
+ "der 0.7.7",
+ "spki 0.7.2",
+]
+
[[package]]
name = "pkg-config"
version = "0.3.27"
@@ -2646,6 +3000,15 @@ dependencies = [
"syn 2.0.28",
]
+[[package]]
+name = "primeorder"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3"
+dependencies = [
+ "elliptic-curve",
+]
+
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@@ -2882,6 +3245,7 @@ dependencies = [
"http",
"http-body",
"hyper",
+ "hyper-rustls 0.24.1",
"hyper-tls",
"ipnet",
"js-sys",
@@ -2891,19 +3255,33 @@ dependencies = [
"once_cell",
"percent-encoding",
"pin-project-lite",
+ "rustls 0.21.6",
+ "rustls-pemfile",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-native-tls",
+ "tokio-rustls 0.24.1",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
+ "webpki-roots",
"winreg",
]
+[[package]]
+name = "rfc6979"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
+dependencies = [
+ "hmac",
+ "subtle",
+]
+
[[package]]
name = "ring"
version = "0.16.20"
@@ -2930,6 +3308,27 @@ dependencies = [
"serde",
]
+[[package]]
+name = "rsa"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "094052d5470cbcef561cb848a7209968c9f12dfa6d668f4bca048ac5de51099c"
+dependencies = [
+ "byteorder",
+ "digest",
+ "num-bigint-dig",
+ "num-integer",
+ "num-iter",
+ "num-traits",
+ "pkcs1",
+ "pkcs8 0.9.0",
+ "rand_core",
+ "signature 1.6.4",
+ "smallvec",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "rstml"
version = "0.11.0"
@@ -3020,6 +3419,18 @@ dependencies = [
"webpki",
]
+[[package]]
+name = "rustls"
+version = "0.21.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb"
+dependencies = [
+ "log",
+ "ring",
+ "rustls-webpki",
+ "sct",
+]
+
[[package]]
name = "rustls-native-certs"
version = "0.6.3"
@@ -3041,6 +3452,16 @@ dependencies = [
"base64 0.21.2",
]
+[[package]]
+name = "rustls-webpki"
+version = "0.101.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
[[package]]
name = "ryu"
version = "1.0.15"
@@ -3090,6 +3511,20 @@ dependencies = [
"untrusted",
]
+[[package]]
+name = "sec1"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
+dependencies = [
+ "base16ct",
+ "der 0.7.7",
+ "generic-array",
+ "pkcs8 0.10.2",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "security-framework"
version = "2.9.2"
@@ -3288,6 +3723,16 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_path_to_error"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335"
+dependencies = [
+ "itoa",
+ "serde",
+]
+
[[package]]
name = "serde_qs"
version = "0.12.0"
@@ -3440,6 +3885,26 @@ dependencies = [
"libc",
]
+[[package]]
+name = "signature"
+version = "1.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+dependencies = [
+ "digest",
+ "rand_core",
+]
+
+[[package]]
+name = "signature"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
+dependencies = [
+ "digest",
+ "rand_core",
+]
+
[[package]]
name = "siphasher"
version = "0.3.10"
@@ -3525,6 +3990,26 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+[[package]]
+name = "spki"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
+dependencies = [
+ "base64ct",
+ "der 0.6.1",
+]
+
+[[package]]
+name = "spki"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
+dependencies = [
+ "base64ct",
+ "der 0.7.7",
+]
+
[[package]]
name = "sqlformat"
version = "0.2.1"
@@ -3583,7 +4068,7 @@ dependencies = [
"paste",
"percent-encoding",
"rand",
- "rustls",
+ "rustls 0.20.8",
"rustls-pemfile",
"serde",
"serde_json",
@@ -3630,7 +4115,7 @@ checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024"
dependencies = [
"once_cell",
"tokio",
- "tokio-rustls",
+ "tokio-rustls 0.23.4",
]
[[package]]
@@ -3872,11 +4357,21 @@ version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
dependencies = [
- "rustls",
+ "rustls 0.20.8",
"tokio",
"webpki",
]
+[[package]]
+name = "tokio-rustls"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
+dependencies = [
+ "rustls 0.21.6",
+ "tokio",
+]
+
[[package]]
name = "tokio-stream"
version = "0.1.14"
@@ -3896,10 +4391,10 @@ checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd"
dependencies = [
"futures-util",
"log",
- "rustls",
+ "rustls 0.20.8",
"rustls-native-certs",
"tokio",
- "tokio-rustls",
+ "tokio-rustls 0.23.4",
"tungstenite",
"webpki",
]
@@ -4001,7 +4496,7 @@ dependencies = [
"httparse",
"log",
"rand",
- "rustls",
+ "rustls 0.20.8",
"sha1",
"thiserror",
"url",
@@ -4019,7 +4514,7 @@ dependencies = [
"flate2",
"futures-util",
"rand",
- "rustls",
+ "rustls 0.20.8",
"rustls-native-certs",
"serde",
"serde_json",
@@ -4049,7 +4544,7 @@ checksum = "5d96e03cd8bca86770e6b3b644ec3938ea85b2c47048412b8767abe4a1ba2a65"
dependencies = [
"brotli",
"hyper",
- "hyper-rustls",
+ "hyper-rustls 0.23.2",
"percent-encoding",
"rand",
"serde",
@@ -4450,11 +4945,13 @@ dependencies = [
"database",
"errors",
"http",
+ "jwt-simple",
"leptos",
"leptos_actix",
"leptos_icons",
"leptos_meta",
"leptos_router",
+ "oauth2",
"once_cell",
"serde",
"twilight-http",
@@ -4608,6 +5105,12 @@ version = "1.0.0-rc"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ee746ad3851dd3bc40e4a028ab3b00b99278d929e48957bcb2d111874a7e43e"
+[[package]]
+name = "zeroize"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
+
[[package]]
name = "zstd"
version = "0.12.4"
diff --git a/crates/common/src/config.rs b/crates/common/src/config.rs
index c34e4d2f..2be7b5d0 100644
--- a/crates/common/src/config.rs
+++ b/crates/common/src/config.rs
@@ -3,18 +3,25 @@ use std::env;
pub struct Config {
pub token: String,
+ pub bot_id: u64,
+
+ pub client_secret: Option,
+ pub redirect_url: Option,
+
+ pub db_url: String,
+ pub proxy: Option,
+
+ pub shards: u64,
+ pub development: bool,
+
pub patreon_token: Option,
pub sentry: Option,
- pub shards: u64,
- pub db_url: String,
+
pub error_channel: Option,
- pub development: bool,
pub owner_ids: Vec,
- pub bot_id: u64,
pub main_guild: Option,
pub patron_role: Option,
pub supporter_role: Option,
- pub proxy: Option,
}
impl Config {
@@ -24,6 +31,8 @@ impl Config {
Err(why) => eprintln!("Failed to load .env: {why}"),
};
let token = env::var("DISCORD_TOKEN").expect("DISCORD_TOKEN not set");
+ let client_secret = env::var("CLIENT_SECRET").ok();
+ let redirect_url = env::var("REDIRECT_URL").ok();
let patreon_token = env::var("PATREON_TOKEN").ok();
let sentry = env::var("SENTRY_URL").ok();
let shards = env::var("SHARDS")
@@ -56,6 +65,8 @@ impl Config {
Config {
token,
+ client_secret,
+ redirect_url,
patreon_token,
sentry,
shards,
diff --git a/crates/website/Cargo.toml b/crates/website/Cargo.toml
index fd65dfbe..9ed9826c 100644
--- a/crates/website/Cargo.toml
+++ b/crates/website/Cargo.toml
@@ -26,8 +26,11 @@ serde = "1.0.181"
once_cell = { version = "1.18.0", optional = true }
twilight-model = "0.15.2"
twilight-http = { version = "0.15.2", optional = true }
+jwt-simple = { version = "0.11.6", optional = true }
+oauth2 = { version = "4.4.1", optional = true }
[features]
+default = ["ssr", "hydrate", "csr"]
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
ssr = [
@@ -39,6 +42,8 @@ ssr = [
"dep:leptos_actix",
"dep:once_cell",
"dep:twilight-http",
+ "dep:jwt-simple",
+ "dep:oauth2",
"leptos/ssr",
"leptos_meta/ssr",
"leptos_router/ssr",
diff --git a/crates/website/src/auth/context.rs b/crates/website/src/auth/context.rs
new file mode 100644
index 00000000..6c471ab5
--- /dev/null
+++ b/crates/website/src/auth/context.rs
@@ -0,0 +1,43 @@
+use actix_web::HttpRequest;
+use jwt_simple::prelude::JWTClaims;
+use leptos::expect_context;
+use twilight_http::Client;
+
+use crate::{expect_config, jwt_key};
+
+use super::jwt::AuthClaims;
+
+#[derive(Debug)]
+pub struct AuthContext {
+ pub http: Client,
+ pub claims: JWTClaims,
+}
+
+impl AuthContext {
+ pub fn build_from_cx(cx: leptos::Scope) -> Option {
+ let req = expect_context::(cx);
+ let key = jwt_key(cx);
+
+ let Some(jwt_cookie) = req.cookie("SessionKey") else {
+ return None;
+ };
+
+ let jwt = jwt_cookie.value();
+ let claims = AuthClaims::verify(jwt, &key)?;
+
+ Some(Self {
+ http: Self::build_http(cx, claims.custom.user_token.secret().to_owned()),
+ claims,
+ })
+ }
+
+ pub fn build_http(cx: leptos::Scope, access_token: String) -> Client {
+ let config = expect_config(cx);
+
+ let mut client = Client::builder().token(format!("Bearer {access_token}"));
+ if let Some(proxy) = config.proxy.clone() {
+ client = client.proxy(proxy, true);
+ }
+ client.build()
+ }
+}
diff --git a/crates/website/src/auth/jwt.rs b/crates/website/src/auth/jwt.rs
new file mode 100644
index 00000000..b9cc2029
--- /dev/null
+++ b/crates/website/src/auth/jwt.rs
@@ -0,0 +1,45 @@
+use jwt_simple::prelude::*;
+use oauth2::AccessToken;
+use serde::{Deserialize, Serialize};
+use twilight_model::id::{marker::UserMarker, Id};
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct AuthClaims {
+ /// The ID of the authenticated user.
+ pub user_id: Id,
+ /// The oauth2 token of the authenticated user.
+ ///
+ /// This is stored, unencrypted, in the cookies
+ /// of the clients browser. This is safe because
+ /// the oauth2 tokens we generate only ever have
+ /// the "identify" and "guilds" scope.
+ pub user_token: AccessToken,
+}
+
+impl AuthClaims {
+ pub fn new(user_id: Id, user_token: AccessToken) -> Self {
+ Self {
+ user_id,
+ user_token,
+ }
+ }
+
+ pub fn sign(self, key: &HS256Key) -> String {
+ let claims = Claims::with_custom_claims(self, Duration::from_hours(2));
+ key.authenticate(claims).unwrap()
+ }
+
+ pub fn verify(token: &str, key: &HS256Key) -> Option> {
+ key.verify_token::(token, None).ok()
+ }
+}
+
+/// Generate a new secret key for signing
+/// JWT claims.
+///
+/// There is a new secret every restart,
+/// meaning that after website restarts,
+/// users will need to sign in again.
+pub fn new_secret() -> HS256Key {
+ HS256Key::generate()
+}
diff --git a/crates/website/src/auth/mod.rs b/crates/website/src/auth/mod.rs
new file mode 100644
index 00000000..04710072
--- /dev/null
+++ b/crates/website/src/auth/mod.rs
@@ -0,0 +1,5 @@
+#[cfg(feature = "ssr")]
+pub mod context;
+#[cfg(feature = "ssr")]
+pub mod jwt;
+pub mod oauth2;
diff --git a/crates/website/src/auth/oauth2.rs b/crates/website/src/auth/oauth2.rs
new file mode 100644
index 00000000..3a9a451b
--- /dev/null
+++ b/crates/website/src/auth/oauth2.rs
@@ -0,0 +1,87 @@
+use leptos::*;
+
+#[cfg(feature = "ssr")]
+use actix_web::{
+ cookie::{Cookie, SameSite},
+ http::header::SET_COOKIE,
+};
+#[cfg(feature = "ssr")]
+use leptos_actix::ResponseOptions;
+#[cfg(feature = "ssr")]
+use oauth2::{
+ http::HeaderValue, reqwest::async_http_client, AuthorizationCode, CsrfToken, Scope,
+ TokenResponse,
+};
+
+#[cfg(feature = "ssr")]
+use crate::{jwt_key, oauth_client};
+
+#[cfg(feature = "ssr")]
+use super::jwt::AuthClaims;
+
+#[cfg(feature = "ssr")]
+fn secure_cookie(name: &str, value: &str) -> HeaderValue {
+ let cookie = Cookie::build(name, value)
+ .permanent()
+ .http_only(true)
+ .secure(true)
+ .same_site(SameSite::Strict)
+ .finish();
+ HeaderValue::from_str(&cookie.to_string()).unwrap()
+}
+
+#[server(BeginAuthFlow, "/api")]
+pub async fn begin_auth_flow(cx: leptos::Scope) -> Result {
+ let client = oauth_client(cx);
+
+ let response = expect_context::(cx);
+
+ let (url, csrf) = client
+ .authorize_url(CsrfToken::new_random)
+ .add_scope(Scope::new("identify".to_string()))
+ .add_scope(Scope::new("guilds".to_string()))
+ .url();
+
+ response.insert_header(
+ SET_COOKIE,
+ secure_cookie("ExpectedOAuth2State", csrf.secret()),
+ );
+
+ Ok(url.to_string())
+}
+
+#[server(FinishAuthFlow, "/api")]
+pub async fn finish_auth_flow(
+ cx: leptos::Scope,
+ code: String,
+ state: String,
+) -> Result<(), ServerFnError> {
+ let req = expect_context::(cx);
+ let response = expect_context::(cx);
+ let client = oauth_client(cx);
+ let jwt_key = jwt_key(cx);
+
+ if req
+ .cookie("ExpectedOAuth2State")
+ .map(|c| c.value().to_string())
+ != Some(state)
+ {
+ return Err(ServerFnError::ServerError("Invalid state".to_string()));
+ }
+
+ let token = client
+ .exchange_code(AuthorizationCode::new(code))
+ .request_async(async_http_client)
+ .await?
+ .access_token()
+ .to_owned();
+
+ let http = twilight_http::Client::new(format!("Bearer {}", token.secret()));
+ let user = http.current_user().await?.model().await?;
+
+ let jwt = AuthClaims::new(user.id, token).sign(&jwt_key);
+
+ response.insert_header(SET_COOKIE, secure_cookie("SessionKey", &jwt));
+
+ Ok(())
+}
diff --git a/crates/website/src/lib.rs b/crates/website/src/lib.rs
index 7908413e..6e3de777 100644
--- a/crates/website/src/lib.rs
+++ b/crates/website/src/lib.rs
@@ -1,20 +1,43 @@
pub mod app;
+pub mod auth;
pub mod site;
pub mod utils;
+#[cfg(feature = "ssr")]
+use std::sync::Arc;
+
+#[cfg(feature = "ssr")]
+use jwt_simple::prelude::HS256Key;
+#[cfg(feature = "ssr")]
+use twilight_http::Client;
+#[cfg(feature = "hydrate")]
+use wasm_bindgen::prelude::wasm_bindgen;
+
+#[cfg(feature = "ssr")]
+pub fn expect_config(cx: leptos::Scope) -> Arc {
+ leptos::expect_context(cx)
+}
+
+#[cfg(feature = "ssr")]
+pub fn jwt_key(cx: leptos::Scope) -> Arc {
+ leptos::expect_context(cx)
+}
+
+#[cfg(feature = "ssr")]
+pub fn oauth_client(cx: leptos::Scope) -> Arc {
+ leptos::expect_context(cx)
+}
+
#[cfg(feature = "ssr")]
pub fn db(cx: leptos::Scope) -> std::sync::Arc {
leptos::use_context(cx).expect("database")
}
#[cfg(feature = "ssr")]
-pub fn http(cx: leptos::Scope) -> std::sync::Arc {
+pub fn bot_http(cx: leptos::Scope) -> Arc {
leptos::use_context(cx).expect("http client")
}
-#[cfg(feature = "hydrate")]
-use wasm_bindgen::prelude::wasm_bindgen;
-
#[cfg(feature = "hydrate")]
#[wasm_bindgen]
pub fn hydrate() {
diff --git a/crates/website/src/main.rs b/crates/website/src/main.rs
index bfe2f8ad..3f6ed73a 100644
--- a/crates/website/src/main.rs
+++ b/crates/website/src/main.rs
@@ -7,8 +7,9 @@ async fn main() -> std::io::Result<()> {
use actix_web::*;
use leptos::*;
use leptos_actix::{generate_route_list, LeptosRoutes};
+ use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl};
use twilight_http::client::Client as HttpClient;
- use website::app::*;
+ use website::{app::*, auth::jwt};
let conf = get_configuration(None).await.unwrap();
let addr = conf.leptos_options.site_addr;
@@ -24,6 +25,7 @@ async fn main() -> std::io::Result<()> {
http = http.proxy(proxy.to_owned(), true);
}
let http = Arc::new(http.build());
+ let jwt_key = Arc::new(jwt::new_secret());
HttpServer::new(move || {
let leptos_options = &conf.leptos_options;
@@ -36,6 +38,33 @@ async fn main() -> std::io::Result<()> {
let http = http.clone();
let http2 = http.clone();
+ let oauth_client = BasicClient::new(
+ ClientId::new(config.bot_id.to_string()),
+ Some(ClientSecret::new(
+ config
+ .client_secret
+ .clone()
+ .expect("CLIENT_SECRET required for website"),
+ )),
+ AuthUrl::new("https://discord.com/oauth2/authorize".to_string()).unwrap(),
+ Some(TokenUrl::new("https://discord.com/api/oauth2/token".to_string()).unwrap()),
+ )
+ .set_redirect_uri(
+ RedirectUrl::new(
+ config
+ .redirect_url
+ .clone()
+ .expect("REDIRECT_URL required for website"),
+ )
+ .unwrap(),
+ );
+
+ let oauth_client = Arc::new(oauth_client);
+ let oauth_client2 = oauth_client.clone();
+
+ let jwt_key = jwt_key.clone();
+ let jwt_key2 = jwt_key.clone();
+
App::new()
.route(
"/api/{tail:.*}",
@@ -43,6 +72,8 @@ async fn main() -> std::io::Result<()> {
provide_context(cx, db.clone());
provide_context(cx, config.clone());
provide_context(cx, http.clone());
+ provide_context(cx, oauth_client.clone());
+ provide_context(cx, jwt_key.clone());
}),
)
// serve JS/WASM/CSS from `pkg`
@@ -55,6 +86,8 @@ async fn main() -> std::io::Result<()> {
provide_context(cx, db2.clone());
provide_context(cx, config2.clone());
provide_context(cx, http2.clone());
+ provide_context(cx, oauth_client2.clone());
+ provide_context(cx, jwt_key2.clone());
view! { cx, }
})
diff --git a/crates/website/src/site/routes/auth/login.rs b/crates/website/src/site/routes/auth/login.rs
new file mode 100644
index 00000000..8cfdae4f
--- /dev/null
+++ b/crates/website/src/site/routes/auth/login.rs
@@ -0,0 +1,43 @@
+use leptos::*;
+use leptos_router::*;
+
+use crate::auth::oauth2::finish_auth_flow;
+
+#[derive(Params, PartialEq, Clone)]
+struct QueryParams {
+ state: String,
+ code: String,
+}
+
+#[component]
+pub fn Login(cx: Scope) -> impl IntoView {
+ let res = create_local_resource(
+ cx,
+ move || use_query::(cx).get().unwrap(),
+ move |params| finish_auth_flow(cx, params.code.clone(), params.state.clone()),
+ );
+
+ view! { cx,
+
+ {move || {
+ res.with(
+ cx,
+ |res| match res {
+ Ok(()) => {
+ if window().location().assign("/servers").is_err() {
+ "Something went wrong."
+ } else {
+ "Redirecting..."
+ }
+ }
+ Err(_) => "Something went wrong.",
+ },
+ )
+ }}
+
+
+ }
+ .into_view(cx)
+}
diff --git a/crates/website/src/site/routes/auth/mod.rs b/crates/website/src/site/routes/auth/mod.rs
new file mode 100644
index 00000000..61103062
--- /dev/null
+++ b/crates/website/src/site/routes/auth/mod.rs
@@ -0,0 +1,2 @@
+pub mod login;
+pub mod redirect;
diff --git a/crates/website/src/site/routes/auth/redirect.rs b/crates/website/src/site/routes/auth/redirect.rs
new file mode 100644
index 00000000..b5e56256
--- /dev/null
+++ b/crates/website/src/site/routes/auth/redirect.rs
@@ -0,0 +1,32 @@
+use leptos::*;
+
+use crate::auth::oauth2::begin_auth_flow;
+
+#[component]
+pub fn Redirect(cx: Scope) -> impl IntoView {
+ let res = create_local_resource(cx, || (), move |_| begin_auth_flow(cx));
+
+ view! { cx,
+
+ {move || {
+ res
+ .with(
+ cx,
+ |url| match url {
+ Err(_) => "Something went wrong.",
+ Ok(url) => {
+ if window().location().assign(url).is_err() {
+ "Something went wrong."
+ } else {
+ "Redirecting..."
+ }
+ }
+ },
+ )
+ }}
+
+
+ }
+}
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index de76bb49..4b15f8ae 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -1,16 +1,40 @@
+pub mod auth;
pub mod servers;
pub mod website;
use leptos::*;
use leptos_router::*;
+use twilight_model::user::CurrentUser;
use super::errors;
+#[server(GetUser, "/api")]
+pub async fn get_user(cx: Scope) -> Result, ServerFnError> {
+ use crate::auth::context::AuthContext;
+ let Some(acx) = AuthContext::build_from_cx(cx) else {
+ return Ok(None);
+ };
+
+ Ok(Some(acx.http.current_user().await?.model().await?))
+}
+
+pub type UserRes = Resource<(), Option>;
+
#[component]
pub fn Index(cx: Scope) -> impl IntoView {
+ let user = create_local_resource(
+ cx,
+ || (),
+ move |_| async move { get_user(cx).await.ok().flatten() },
+ );
+ provide_context(cx, user);
+
view! { cx,
+
+
+
diff --git a/crates/website/src/site/routes/servers/id/mod.rs b/crates/website/src/site/routes/servers/id/mod.rs
index 9b22773d..933d85bf 100644
--- a/crates/website/src/site/routes/servers/id/mod.rs
+++ b/crates/website/src/site/routes/servers/id/mod.rs
@@ -7,6 +7,9 @@ use leptos_router::*;
use serde::{Deserialize, Serialize};
use twilight_model::guild::Guild;
+#[cfg(feature = "ssr")]
+use twilight_model::id::Id;
+
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GuildData {
pub db: DbGuild,
@@ -17,10 +20,8 @@ pub type GuildContext = Resource>;
#[server(GetGuild, "/api")]
pub async fn get_guild(cx: Scope, id: u64) -> Result, ServerFnError> {
- use twilight_model::id::Id;
-
let db = crate::db(cx);
- let http = crate::http(cx);
+ let http = crate::bot_http(cx);
let http_guild = match http.guild(Id::new(id)).await {
Ok(res) => res.model().await?,
@@ -54,7 +55,7 @@ struct Props {
pub fn Server(cx: Scope) -> impl IntoView {
let params = use_params::(cx);
let id = move || params.with(|p| p.as_ref().unwrap().id);
- let guild = create_resource(cx, id, move |id| async move {
+ let guild = create_local_resource(cx, id, move |id| async move {
get_guild(cx, id).await.ok().flatten()
});
provide_context(cx, guild);
diff --git a/crates/website/src/site/routes/servers/mod.rs b/crates/website/src/site/routes/servers/mod.rs
index 1e4faa7d..fe2ed7e0 100644
--- a/crates/website/src/site/routes/servers/mod.rs
+++ b/crates/website/src/site/routes/servers/mod.rs
@@ -2,9 +2,30 @@ pub mod id;
pub mod server_list;
use leptos::*;
-use leptos_router::Outlet;
+use leptos_router::*;
+
+use super::UserRes;
#[component]
pub fn Servers(cx: Scope) -> impl IntoView {
- view! { cx, }
+ let user = expect_context::(cx);
+
+ view! { cx,
+
+ {move || {
+ user.with(
+ cx,
+ |user| {
+ if user.is_none() {
+ Some(view! { cx, })
+ } else {
+ None
+ }
+ },
+ )
+ }}
+
+
+
+ }
}
From 81c866e5c79de326e1b2c9db16f6a6c6b534dfce Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Sat, 5 Aug 2023 21:40:00 -0400
Subject: [PATCH 024/119] fix cookie related things
---
crates/website/src/auth/context.rs | 4 +--
crates/website/src/auth/oauth2.rs | 14 +++++---
crates/website/src/site/routes/auth/login.rs | 14 ++++----
.../website/src/site/routes/auth/redirect.rs | 32 ++++++++++---------
crates/website/src/site/routes/mod.rs | 2 +-
.../website/src/site/routes/servers/id/mod.rs | 4 +--
.../src/site/routes/servers/id/overview.rs | 4 +--
.../src/site/routes/servers/server_list.rs | 2 +-
8 files changed, 42 insertions(+), 34 deletions(-)
diff --git a/crates/website/src/auth/context.rs b/crates/website/src/auth/context.rs
index 6c471ab5..738ff34c 100644
--- a/crates/website/src/auth/context.rs
+++ b/crates/website/src/auth/context.rs
@@ -1,6 +1,6 @@
use actix_web::HttpRequest;
use jwt_simple::prelude::JWTClaims;
-use leptos::expect_context;
+use leptos::*;
use twilight_http::Client;
use crate::{expect_config, jwt_key};
@@ -15,7 +15,7 @@ pub struct AuthContext {
impl AuthContext {
pub fn build_from_cx(cx: leptos::Scope) -> Option {
- let req = expect_context::(cx);
+ let req = use_context::(cx)?;
let key = jwt_key(cx);
let Some(jwt_cookie) = req.cookie("SessionKey") else {
diff --git a/crates/website/src/auth/oauth2.rs b/crates/website/src/auth/oauth2.rs
index 3a9a451b..2d39b65f 100644
--- a/crates/website/src/auth/oauth2.rs
+++ b/crates/website/src/auth/oauth2.rs
@@ -20,12 +20,16 @@ use crate::{jwt_key, oauth_client};
use super::jwt::AuthClaims;
#[cfg(feature = "ssr")]
-fn secure_cookie(name: &str, value: &str) -> HeaderValue {
+fn secure_cookie(name: &str, value: &str, samesite: bool) -> HeaderValue {
let cookie = Cookie::build(name, value)
- .permanent()
.http_only(true)
.secure(true)
- .same_site(SameSite::Strict)
+ .same_site(if samesite {
+ SameSite::Strict
+ } else {
+ SameSite::Lax
+ })
+ .path("/")
.finish();
HeaderValue::from_str(&cookie.to_string()).unwrap()
}
@@ -44,7 +48,7 @@ pub async fn begin_auth_flow(cx: leptos::Scope) -> Result
response.insert_header(
SET_COOKIE,
- secure_cookie("ExpectedOAuth2State", csrf.secret()),
+ secure_cookie("ExpectedOAuth2State", csrf.secret(), false),
);
Ok(url.to_string())
@@ -81,7 +85,7 @@ pub async fn finish_auth_flow(
let jwt = AuthClaims::new(user.id, token).sign(&jwt_key);
- response.insert_header(SET_COOKIE, secure_cookie("SessionKey", &jwt));
+ response.insert_header(SET_COOKIE, secure_cookie("SessionKey", &jwt, true));
Ok(())
}
diff --git a/crates/website/src/site/routes/auth/login.rs b/crates/website/src/site/routes/auth/login.rs
index 8cfdae4f..fd1410ca 100644
--- a/crates/website/src/site/routes/auth/login.rs
+++ b/crates/website/src/site/routes/auth/login.rs
@@ -11,7 +11,7 @@ struct QueryParams {
#[component]
pub fn Login(cx: Scope) -> impl IntoView {
- let res = create_local_resource(
+ let res = create_blocking_resource(
cx,
move || use_query::(cx).get().unwrap(),
move |params| finish_auth_flow(cx, params.code.clone(), params.state.clone()),
@@ -26,11 +26,13 @@ pub fn Login(cx: Scope) -> impl IntoView {
cx,
|res| match res {
Ok(()) => {
- if window().location().assign("/servers").is_err() {
- "Something went wrong."
- } else {
- "Redirecting..."
- }
+ create_effect(
+ cx,
+ move |_| {
+ window().location().assign("/servers").unwrap();
+ },
+ );
+ "Redirecting..."
}
Err(_) => "Something went wrong.",
},
diff --git a/crates/website/src/site/routes/auth/redirect.rs b/crates/website/src/site/routes/auth/redirect.rs
index b5e56256..aa12b5a9 100644
--- a/crates/website/src/site/routes/auth/redirect.rs
+++ b/crates/website/src/site/routes/auth/redirect.rs
@@ -4,27 +4,29 @@ use crate::auth::oauth2::begin_auth_flow;
#[component]
pub fn Redirect(cx: Scope) -> impl IntoView {
- let res = create_local_resource(cx, || (), move |_| begin_auth_flow(cx));
+ let res = create_blocking_resource(cx, || (), move |_| begin_auth_flow(cx));
view! { cx,
{move || {
- res
- .with(
- cx,
- |url| match url {
- Err(_) => "Something went wrong.",
- Ok(url) => {
- if window().location().assign(url).is_err() {
- "Something went wrong."
- } else {
- "Redirecting..."
- }
- }
- },
- )
+ res.with(
+ cx,
+ |url| match url {
+ Err(_) => "Something went wrong.",
+ Ok(url) => {
+ let url = url.to_owned();
+ create_effect(
+ cx,
+ move |_| {
+ window().location().assign(&url).unwrap();
+ },
+ );
+ "Redirecting..."
+ }
+ },
+ )
}}
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index 4b15f8ae..6d0ba2f2 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -22,7 +22,7 @@ pub type UserRes = Resource<(), Option>;
#[component]
pub fn Index(cx: Scope) -> impl IntoView {
- let user = create_local_resource(
+ let user = create_resource(
cx,
|| (),
move |_| async move { get_user(cx).await.ok().flatten() },
diff --git a/crates/website/src/site/routes/servers/id/mod.rs b/crates/website/src/site/routes/servers/id/mod.rs
index 933d85bf..9f0f54bb 100644
--- a/crates/website/src/site/routes/servers/id/mod.rs
+++ b/crates/website/src/site/routes/servers/id/mod.rs
@@ -55,7 +55,7 @@ struct Props {
pub fn Server(cx: Scope) -> impl IntoView {
let params = use_params::(cx);
let id = move || params.with(|p| p.as_ref().unwrap().id);
- let guild = create_local_resource(cx, id, move |id| async move {
+ let guild = create_resource(cx, id, move |id| async move {
get_guild(cx, id).await.ok().flatten()
});
provide_context(cx, guild);
@@ -94,7 +94,7 @@ fn ServerNavBar(cx: Scope) -> impl IntoView {
diff --git a/crates/website/src/site/routes/servers/id/overview.rs b/crates/website/src/site/routes/servers/id/overview.rs
index d0051cbd..8986f8b3 100644
--- a/crates/website/src/site/routes/servers/id/overview.rs
+++ b/crates/website/src/site/routes/servers/id/overview.rs
@@ -4,6 +4,6 @@ use leptos::*;
pub fn Overview(cx: Scope) -> impl IntoView {
let guild = expect_context::(cx);
- let content = move || format!("{:?}", guild.read(cx));
- view! { cx, {content} }
+ let content = move || guild.with(cx, |g| format!("{g:?}"));
+ view! { cx, {content} }
}
diff --git a/crates/website/src/site/routes/servers/server_list.rs b/crates/website/src/site/routes/servers/server_list.rs
index ea72ca0d..181555ca 100644
--- a/crates/website/src/site/routes/servers/server_list.rs
+++ b/crates/website/src/site/routes/servers/server_list.rs
@@ -10,7 +10,7 @@ pub fn ServerList(cx: Scope) -> impl IntoView {
-
+
"Go to server"
From fb607f6e89749be6efdfdb1a624ddff7fd1e4100 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Sun, 6 Aug 2023 19:09:20 -0400
Subject: [PATCH 025/119] stuffs
---
Cargo.lock | 1 +
crates/website/Cargo.toml | 2 +
crates/website/src/auth/context.rs | 46 ++++++++++++-------
crates/website/src/auth/jwt.rs | 9 ++--
crates/website/src/auth/oauth2.rs | 10 +++-
crates/website/src/lib.rs | 18 +++++++-
crates/website/src/main.rs | 12 ++++-
crates/website/src/site/routes/auth/login.rs | 44 ++++++++++--------
.../website/src/site/routes/auth/redirect.rs | 46 ++++++++++---------
crates/website/src/site/routes/mod.rs | 18 +++-----
.../website/src/site/routes/servers/id/mod.rs | 27 ++++++-----
crates/website/src/site/routes/servers/mod.rs | 2 +-
.../src/site/routes/servers/server_list.rs | 32 +++++++++++++
13 files changed, 178 insertions(+), 89 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 31e95004..dd5a1b06 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4953,6 +4953,7 @@ dependencies = [
"leptos_router",
"oauth2",
"once_cell",
+ "parking_lot 0.12.1",
"serde",
"twilight-http",
"twilight-model",
diff --git a/crates/website/Cargo.toml b/crates/website/Cargo.toml
index 9ed9826c..cfa25475 100644
--- a/crates/website/Cargo.toml
+++ b/crates/website/Cargo.toml
@@ -28,6 +28,7 @@ twilight-model = "0.15.2"
twilight-http = { version = "0.15.2", optional = true }
jwt-simple = { version = "0.11.6", optional = true }
oauth2 = { version = "4.4.1", optional = true }
+parking_lot = {version = "0.12.1", optional = true }
[features]
default = ["ssr", "hydrate", "csr"]
@@ -44,6 +45,7 @@ ssr = [
"dep:twilight-http",
"dep:jwt-simple",
"dep:oauth2",
+ "dep:parking_lot",
"leptos/ssr",
"leptos_meta/ssr",
"leptos_router/ssr",
diff --git a/crates/website/src/auth/context.rs b/crates/website/src/auth/context.rs
index 738ff34c..c1be1a44 100644
--- a/crates/website/src/auth/context.rs
+++ b/crates/website/src/auth/context.rs
@@ -1,9 +1,11 @@
+use std::sync::Arc;
+
use actix_web::HttpRequest;
use jwt_simple::prelude::JWTClaims;
use leptos::*;
use twilight_http::Client;
-use crate::{expect_config, jwt_key};
+use crate::{expect_auth_states, jwt_key};
use super::jwt::AuthClaims;
@@ -14,30 +16,42 @@ pub struct AuthContext {
}
impl AuthContext {
- pub fn build_from_cx(cx: leptos::Scope) -> Option {
+ pub fn provide(self, cx: leptos::Scope) -> Arc {
+ let states = expect_auth_states(cx);
+ let acx = Arc::new(self);
+ states
+ .write()
+ .insert(acx.claims.custom.user_id, acx.clone());
+ acx
+ }
+
+ pub fn get(cx: leptos::Scope) -> Option> {
let req = use_context::(cx)?;
let key = jwt_key(cx);
+ let Some(session) = req.cookie("SessionKey") else {
+ return None;
+ };
+ let claims = AuthClaims::verify(session.value(), &key)?;
- let Some(jwt_cookie) = req.cookie("SessionKey") else {
+ let state = {
+ let states = expect_auth_states(cx);
+ let states = states.read();
+ states.get(&claims.custom.user_id).cloned()
+ };
+
+ let Some(state) = state else {
return None;
};
- let jwt = jwt_cookie.value();
- let claims = AuthClaims::verify(jwt, &key)?;
+ if claims.nonce != state.claims.nonce {
+ return None;
+ }
- Some(Self {
- http: Self::build_http(cx, claims.custom.user_token.secret().to_owned()),
- claims,
- })
+ Some(state)
}
- pub fn build_http(cx: leptos::Scope, access_token: String) -> Client {
- let config = expect_config(cx);
-
- let mut client = Client::builder().token(format!("Bearer {access_token}"));
- if let Some(proxy) = config.proxy.clone() {
- client = client.proxy(proxy, true);
- }
+ pub fn build_http(access_token: &str) -> Client {
+ let client = Client::builder().token(format!("Bearer {access_token}"));
client.build()
}
}
diff --git a/crates/website/src/auth/jwt.rs b/crates/website/src/auth/jwt.rs
index b9cc2029..ffd89740 100644
--- a/crates/website/src/auth/jwt.rs
+++ b/crates/website/src/auth/jwt.rs
@@ -3,7 +3,7 @@ use oauth2::AccessToken;
use serde::{Deserialize, Serialize};
use twilight_model::id::{marker::UserMarker, Id};
-#[derive(Serialize, Deserialize, Debug)]
+#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct AuthClaims {
/// The ID of the authenticated user.
pub user_id: Id,
@@ -24,9 +24,10 @@ impl AuthClaims {
}
}
- pub fn sign(self, key: &HS256Key) -> String {
- let claims = Claims::with_custom_claims(self, Duration::from_hours(2));
- key.authenticate(claims).unwrap()
+ pub fn build(self) -> JWTClaims {
+ let mut claims = Claims::with_custom_claims(self, Duration::from_hours(2));
+ claims.create_nonce();
+ claims
}
pub fn verify(token: &str, key: &HS256Key) -> Option> {
diff --git a/crates/website/src/auth/oauth2.rs b/crates/website/src/auth/oauth2.rs
index 2d39b65f..480b4a00 100644
--- a/crates/website/src/auth/oauth2.rs
+++ b/crates/website/src/auth/oauth2.rs
@@ -6,6 +6,8 @@ use actix_web::{
http::header::SET_COOKIE,
};
#[cfg(feature = "ssr")]
+use jwt_simple::prelude::MACLike;
+#[cfg(feature = "ssr")]
use leptos_actix::ResponseOptions;
#[cfg(feature = "ssr")]
use oauth2::{
@@ -16,6 +18,8 @@ use oauth2::{
#[cfg(feature = "ssr")]
use crate::{jwt_key, oauth_client};
+#[cfg(feature = "ssr")]
+use super::context::AuthContext;
#[cfg(feature = "ssr")]
use super::jwt::AuthClaims;
@@ -83,7 +87,11 @@ pub async fn finish_auth_flow(
let http = twilight_http::Client::new(format!("Bearer {}", token.secret()));
let user = http.current_user().await?.model().await?;
- let jwt = AuthClaims::new(user.id, token).sign(&jwt_key);
+ let claims = AuthClaims::new(user.id, token).build();
+ let jwt = jwt_key.authenticate(claims.clone()).unwrap();
+
+ let acx = AuthContext { http, claims };
+ acx.provide(cx);
response.insert_header(SET_COOKIE, secure_cookie("SessionKey", &jwt, true));
diff --git a/crates/website/src/lib.rs b/crates/website/src/lib.rs
index 6e3de777..42334a32 100644
--- a/crates/website/src/lib.rs
+++ b/crates/website/src/lib.rs
@@ -4,15 +4,31 @@ pub mod site;
pub mod utils;
#[cfg(feature = "ssr")]
-use std::sync::Arc;
+use std::{collections::HashMap, sync::Arc};
+#[cfg(feature = "ssr")]
+use auth::context::AuthContext;
#[cfg(feature = "ssr")]
use jwt_simple::prelude::HS256Key;
#[cfg(feature = "ssr")]
+use parking_lot::RwLock;
+#[cfg(feature = "ssr")]
use twilight_http::Client;
+#[cfg(feature = "ssr")]
+use twilight_model::id::marker::UserMarker;
+#[cfg(feature = "ssr")]
+use twilight_model::id::Id;
#[cfg(feature = "hydrate")]
use wasm_bindgen::prelude::wasm_bindgen;
+#[cfg(feature = "ssr")]
+pub type AuthStates = Arc, Arc>>>;
+
+#[cfg(feature = "ssr")]
+pub fn expect_auth_states(cx: leptos::Scope) -> AuthStates {
+ leptos::expect_context(cx)
+}
+
#[cfg(feature = "ssr")]
pub fn expect_config(cx: leptos::Scope) -> Arc {
leptos::expect_context(cx)
diff --git a/crates/website/src/main.rs b/crates/website/src/main.rs
index 3f6ed73a..13b1f1e6 100644
--- a/crates/website/src/main.rs
+++ b/crates/website/src/main.rs
@@ -1,15 +1,16 @@
#[cfg(feature = "ssr")]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
- use std::{sync::Arc, time::Duration};
+ use std::{collections::HashMap, sync::Arc, time::Duration};
use actix_files::Files;
use actix_web::*;
use leptos::*;
use leptos_actix::{generate_route_list, LeptosRoutes};
use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl};
+ use parking_lot::RwLock;
use twilight_http::client::Client as HttpClient;
- use website::{app::*, auth::jwt};
+ use website::{app::*, auth::jwt, AuthStates};
let conf = get_configuration(None).await.unwrap();
let addr = conf.leptos_options.site_addr;
@@ -27,6 +28,8 @@ async fn main() -> std::io::Result<()> {
let http = Arc::new(http.build());
let jwt_key = Arc::new(jwt::new_secret());
+ let auth_states: AuthStates = Arc::new(RwLock::new(HashMap::new()));
+
HttpServer::new(move || {
let leptos_options = &conf.leptos_options;
let site_root = &leptos_options.site_root;
@@ -38,6 +41,9 @@ async fn main() -> std::io::Result<()> {
let http = http.clone();
let http2 = http.clone();
+ let auth_states = auth_states.clone();
+ let auth_states2 = auth_states.clone();
+
let oauth_client = BasicClient::new(
ClientId::new(config.bot_id.to_string()),
Some(ClientSecret::new(
@@ -74,6 +80,7 @@ async fn main() -> std::io::Result<()> {
provide_context(cx, http.clone());
provide_context(cx, oauth_client.clone());
provide_context(cx, jwt_key.clone());
+ provide_context(cx, auth_states.clone());
}),
)
// serve JS/WASM/CSS from `pkg`
@@ -88,6 +95,7 @@ async fn main() -> std::io::Result<()> {
provide_context(cx, http2.clone());
provide_context(cx, oauth_client2.clone());
provide_context(cx, jwt_key2.clone());
+ provide_context(cx, auth_states2.clone());
view! { cx, }
})
diff --git a/crates/website/src/site/routes/auth/login.rs b/crates/website/src/site/routes/auth/login.rs
index fd1410ca..d443aa47 100644
--- a/crates/website/src/site/routes/auth/login.rs
+++ b/crates/website/src/site/routes/auth/login.rs
@@ -18,27 +18,31 @@ pub fn Login(cx: Scope) -> impl IntoView {
);
view! { cx,
-
- {move || {
- res.with(
- cx,
- |res| match res {
- Ok(()) => {
- create_effect(
- cx,
- move |_| {
- window().location().assign("/servers").unwrap();
- },
- );
- "Redirecting..."
- }
- Err(_) => "Something went wrong.",
- },
- )
- }}
+
+
+ {move || {
+ res
+ .with(
+ cx,
+ move |res| {
+ res
+ .clone()
+ .map(move |_| {
+ create_effect(
+ cx,
+ |_| {
+ window().location().assign("/servers").unwrap();
+ },
+ );
+ "Redirecting..."
+ })
+ },
+ )
+ }}
+
}
.into_view(cx)
diff --git a/crates/website/src/site/routes/auth/redirect.rs b/crates/website/src/site/routes/auth/redirect.rs
index aa12b5a9..8a2f6bf4 100644
--- a/crates/website/src/site/routes/auth/redirect.rs
+++ b/crates/website/src/site/routes/auth/redirect.rs
@@ -3,32 +3,34 @@ use leptos::*;
use crate::auth::oauth2::begin_auth_flow;
#[component]
-pub fn Redirect(cx: Scope) -> impl IntoView {
+pub fn AuthRedirect(cx: Scope) -> impl IntoView {
let res = create_blocking_resource(cx, || (), move |_| begin_auth_flow(cx));
view! { cx,
-
- {move || {
- res.with(
- cx,
- |url| match url {
- Err(_) => "Something went wrong.",
- Ok(url) => {
- let url = url.to_owned();
- create_effect(
- cx,
- move |_| {
- window().location().assign(&url).unwrap();
- },
- );
- "Redirecting..."
- }
- },
- )
- }}
+
+
+ {move || {
+ res.with(
+ cx,
+ move |url| {
+ url
+ .clone()
+ .map(|url| {
+ create_effect(
+ cx,
+ move |_| {
+ window().location().assign(&url).unwrap();
+ },
+ );
+ view! { cx, "Redirecting..." }
+ })
+ },
+ )
+ }}
+
}
}
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index 6d0ba2f2..9cfea06e 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -9,30 +9,26 @@ use twilight_model::user::CurrentUser;
use super::errors;
#[server(GetUser, "/api")]
-pub async fn get_user(cx: Scope) -> Result, ServerFnError> {
+pub async fn get_user(cx: Scope) -> Result {
use crate::auth::context::AuthContext;
- let Some(acx) = AuthContext::build_from_cx(cx) else {
- return Ok(None);
+ let Some(acx) = AuthContext::get(cx) else {
+ return Err(ServerFnError::ServerError("Unauthorized.".to_string()));
};
- Ok(Some(acx.http.current_user().await?.model().await?))
+ Ok(acx.http.current_user().await?.model().await?)
}
-pub type UserRes = Resource<(), Option>;
+pub type UserRes = Resource<(), Result>;
#[component]
pub fn Index(cx: Scope) -> impl IntoView {
- let user = create_resource(
- cx,
- || (),
- move |_| async move { get_user(cx).await.ok().flatten() },
- );
+ let user: UserRes = create_resource(cx, || (), move |_| get_user(cx));
provide_context(cx, user);
view! { cx,
-
+
diff --git a/crates/website/src/site/routes/servers/id/mod.rs b/crates/website/src/site/routes/servers/id/mod.rs
index 9f0f54bb..0c19f9de 100644
--- a/crates/website/src/site/routes/servers/id/mod.rs
+++ b/crates/website/src/site/routes/servers/id/mod.rs
@@ -5,10 +5,7 @@ use leptos::*;
use leptos_icons::*;
use leptos_router::*;
use serde::{Deserialize, Serialize};
-use twilight_model::guild::Guild;
-
-#[cfg(feature = "ssr")]
-use twilight_model::id::Id;
+use twilight_model::{guild::Guild, id::Id};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GuildData {
@@ -16,7 +13,7 @@ pub struct GuildData {
pub http: Guild,
}
-pub type GuildContext = Resource>;
+pub type GuildContext = Resource, ServerFnError>>;
#[server(GetGuild, "/api")]
pub async fn get_guild(cx: Scope, id: u64) -> Result, ServerFnError> {
@@ -54,15 +51,16 @@ struct Props {
#[component]
pub fn Server(cx: Scope) -> impl IntoView {
let params = use_params::(cx);
- let id = move || params.with(|p| p.as_ref().unwrap().id);
- let guild = create_resource(cx, id, move |id| async move {
- get_guild(cx, id).await.ok().flatten()
- });
+ let guild: GuildContext = create_resource(
+ cx,
+ move || params.with(|p| p.as_ref().unwrap().id),
+ move |id| get_guild(cx, id),
+ );
provide_context(cx, guild);
let red = move || {
guild.with(cx, |g| {
- if !g.is_some() {
+ if matches!(g, Ok(None)) {
Some(Redirect(
cx,
RedirectProps::builder().path("/servers").build(),
@@ -88,7 +86,14 @@ pub fn Server(cx: Scope) -> impl IntoView {
fn ServerNavBar(cx: Scope) -> impl IntoView {
let guild = expect_context::(cx);
- let title = move || guild.with(cx, |g| g.as_ref().map(|g| g.http.name.to_owned()));
+ let title = move || {
+ guild.with(cx, |g| {
+ g.as_ref()
+ .ok()
+ .and_then(|g| g.as_ref())
+ .map(|g| g.http.name.to_owned())
+ })
+ };
view! { cx,
diff --git a/crates/website/src/site/routes/servers/mod.rs b/crates/website/src/site/routes/servers/mod.rs
index fe2ed7e0..b5d5ec18 100644
--- a/crates/website/src/site/routes/servers/mod.rs
+++ b/crates/website/src/site/routes/servers/mod.rs
@@ -16,7 +16,7 @@ pub fn Servers(cx: Scope) -> impl IntoView {
user.with(
cx,
|user| {
- if user.is_none() {
+ if user.is_err() {
Some(view! { cx,
})
} else {
None
diff --git a/crates/website/src/site/routes/servers/server_list.rs b/crates/website/src/site/routes/servers/server_list.rs
index 181555ca..e62111fa 100644
--- a/crates/website/src/site/routes/servers/server_list.rs
+++ b/crates/website/src/site/routes/servers/server_list.rs
@@ -1,10 +1,41 @@
+use std::collections::HashMap;
+
use leptos::*;
use leptos_router::*;
+use twilight_model::{
+ id::{marker::GuildMarker, Id},
+ user::CurrentUserGuild,
+};
use crate::site::components::NavBar;
+#[server(GetGuilds, "/api")]
+pub async fn get_guilds(
+ cx: Scope,
+) -> Result
, CurrentUserGuild>, ServerFnError> {
+ use crate::auth::context::AuthContext;
+
+ let Some(auth) = AuthContext::get(cx) else {
+ return Err(ServerFnError::ServerError("Unauthorized.".to_string()));
+ };
+
+ let new_guilds: HashMap<_, _> = auth
+ .http
+ .current_user_guilds()
+ .await?
+ .models()
+ .await?
+ .into_iter()
+ .map(|g| (g.id, g))
+ .collect();
+
+ Ok(new_guilds)
+}
+
#[component]
pub fn ServerList(cx: Scope) -> impl IntoView {
+ let guilds = create_resource(cx, move || (), move |_| get_guilds(cx));
+
view! { cx,
@@ -13,6 +44,7 @@ pub fn ServerList(cx: Scope) -> impl IntoView {
"Go to server"
+ {move || guilds.with(cx, |d| format!("{d:?}"))}
}
}
From 217c835385cb2727050163a800b89297162a9e2d Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Sun, 6 Aug 2023 21:20:40 -0400
Subject: [PATCH 026/119] oauth2 flow improvements
---
crates/website/src/auth/oauth2.rs | 38 +++++++++++++------
crates/website/src/site/routes/auth/login.rs | 32 ++++++++--------
.../website/src/site/routes/auth/redirect.rs | 3 +-
crates/website/src/site/routes/mod.rs | 11 ++++--
crates/website/src/site/routes/servers/mod.rs | 25 +++++-------
5 files changed, 60 insertions(+), 49 deletions(-)
diff --git a/crates/website/src/auth/oauth2.rs b/crates/website/src/auth/oauth2.rs
index 480b4a00..eafdb0de 100644
--- a/crates/website/src/auth/oauth2.rs
+++ b/crates/website/src/auth/oauth2.rs
@@ -1,5 +1,7 @@
use leptos::*;
+#[cfg(feature = "ssr")]
+use actix_web::web::Query;
#[cfg(feature = "ssr")]
use actix_web::{
cookie::{Cookie, SameSite},
@@ -8,12 +10,16 @@ use actix_web::{
#[cfg(feature = "ssr")]
use jwt_simple::prelude::MACLike;
#[cfg(feature = "ssr")]
+use leptos_actix::redirect;
+#[cfg(feature = "ssr")]
use leptos_actix::ResponseOptions;
#[cfg(feature = "ssr")]
use oauth2::{
http::HeaderValue, reqwest::async_http_client, AuthorizationCode, CsrfToken, Scope,
TokenResponse,
};
+#[cfg(feature = "ssr")]
+use serde::Deserialize;
#[cfg(feature = "ssr")]
use crate::{jwt_key, oauth_client};
@@ -38,8 +44,8 @@ fn secure_cookie(name: &str, value: &str, samesite: bool) -> HeaderValue {
HeaderValue::from_str(&cookie.to_string()).unwrap()
}
-#[server(BeginAuthFlow, "/api")]
-pub async fn begin_auth_flow(cx: leptos::Scope) -> Result {
+#[server(BeginAuthFlow, "/api", "Url", "redirect")]
+pub async fn begin_auth_flow(cx: leptos::Scope) -> Result<(), ServerFnError> {
let client = oauth_client(cx);
let response = expect_context::(cx);
@@ -55,30 +61,37 @@ pub async fn begin_auth_flow(cx: leptos::Scope) -> Result
secure_cookie("ExpectedOAuth2State", csrf.secret(), false),
);
- Ok(url.to_string())
+ redirect(cx, url.as_ref());
+
+ Ok(())
}
-#[server(FinishAuthFlow, "/api")]
-pub async fn finish_auth_flow(
- cx: leptos::Scope,
- code: String,
+#[cfg(feature = "ssr")]
+#[derive(Deserialize)]
+struct QueryParams {
state: String,
-) -> Result<(), ServerFnError> {
+ code: String,
+}
+
+#[server(FinishAuthFlow, "/api", "Url", "login")]
+pub async fn finish_auth_flow(cx: leptos::Scope) -> Result<(), ServerFnError> {
let req = expect_context::(cx);
let response = expect_context::(cx);
let client = oauth_client(cx);
let jwt_key = jwt_key(cx);
- if req
+ let query = Query::::from_query(req.query_string())?;
+
+ if !req
.cookie("ExpectedOAuth2State")
- .map(|c| c.value().to_string())
- != Some(state)
+ .map(|c| c.value() == query.state)
+ .unwrap_or(false)
{
return Err(ServerFnError::ServerError("Invalid state".to_string()));
}
let token = client
- .exchange_code(AuthorizationCode::new(code))
+ .exchange_code(AuthorizationCode::new(query.code.clone()))
.request_async(async_http_client)
.await?
.access_token()
@@ -94,6 +107,7 @@ pub async fn finish_auth_flow(
acx.provide(cx);
response.insert_header(SET_COOKIE, secure_cookie("SessionKey", &jwt, true));
+ redirect(cx, "/redirect-to-servers");
Ok(())
}
diff --git a/crates/website/src/site/routes/auth/login.rs b/crates/website/src/site/routes/auth/login.rs
index d443aa47..145b4584 100644
--- a/crates/website/src/site/routes/auth/login.rs
+++ b/crates/website/src/site/routes/auth/login.rs
@@ -23,23 +23,21 @@ pub fn Login(cx: Scope) -> impl IntoView {
"Something went wrong."
}>
{move || {
- res
- .with(
- cx,
- move |res| {
- res
- .clone()
- .map(move |_| {
- create_effect(
- cx,
- |_| {
- window().location().assign("/servers").unwrap();
- },
- );
- "Redirecting..."
- })
- },
- )
+ res.with(
+ cx,
+ move |res| {
+ res.clone()
+ .map(move |_| {
+ create_effect(
+ cx,
+ |_| {
+ window().location().assign("/servers").unwrap();
+ },
+ );
+ "Redirecting..."
+ })
+ },
+ )
}}
diff --git a/crates/website/src/site/routes/auth/redirect.rs b/crates/website/src/site/routes/auth/redirect.rs
index 8a2f6bf4..0a52188d 100644
--- a/crates/website/src/site/routes/auth/redirect.rs
+++ b/crates/website/src/site/routes/auth/redirect.rs
@@ -15,8 +15,7 @@ pub fn AuthRedirect(cx: Scope) -> impl IntoView {
res.with(
cx,
move |url| {
- url
- .clone()
+ url.clone()
.map(|url| {
create_effect(
cx,
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index 9cfea06e..324cc7e9 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -1,4 +1,3 @@
-pub mod auth;
pub mod servers;
pub mod website;
@@ -28,8 +27,7 @@ pub fn Index(cx: Scope) -> impl IntoView {
view! { cx,
-
-
+
@@ -38,6 +36,13 @@ pub fn Index(cx: Scope) -> impl IntoView {
}
}
+#[component]
+fn RedirectToServers(cx: Scope) -> impl IntoView {
+ create_effect(cx, |_| window().location().assign("/servers"));
+
+ view! { cx, "Redirecting..." }
+}
+
#[component(transparent)]
fn WebsiteRoutes(cx: Scope) -> impl IntoView {
view! { cx,
diff --git a/crates/website/src/site/routes/servers/mod.rs b/crates/website/src/site/routes/servers/mod.rs
index b5d5ec18..c19603a7 100644
--- a/crates/website/src/site/routes/servers/mod.rs
+++ b/crates/website/src/site/routes/servers/mod.rs
@@ -10,22 +10,17 @@ use super::UserRes;
pub fn Servers(cx: Scope) -> impl IntoView {
let user = expect_context::(cx);
+ let red = move || {
+ user.with(cx, |u| {
+ if u.is_err() {
+ create_effect(cx, |_| {
+ window().location().assign("/api/redirect").unwrap();
+ })
+ }
+ });
+ };
view! { cx,
-
- {move || {
- user.with(
- cx,
- |user| {
- if user.is_err() {
- Some(view! { cx, })
- } else {
- None
- }
- },
- )
- }}
-
-
+ {red}
}
}
From 5b69c8231bad55d74e32869d78b722b2dcf97b56 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Sun, 6 Aug 2023 21:22:29 -0400
Subject: [PATCH 027/119] remove unused files & imports
---
crates/website/src/site/routes/auth/login.rs | 47 -------------------
crates/website/src/site/routes/auth/mod.rs | 2 -
.../website/src/site/routes/auth/redirect.rs | 35 --------------
.../website/src/site/routes/servers/id/mod.rs | 4 +-
4 files changed, 3 insertions(+), 85 deletions(-)
delete mode 100644 crates/website/src/site/routes/auth/login.rs
delete mode 100644 crates/website/src/site/routes/auth/mod.rs
delete mode 100644 crates/website/src/site/routes/auth/redirect.rs
diff --git a/crates/website/src/site/routes/auth/login.rs b/crates/website/src/site/routes/auth/login.rs
deleted file mode 100644
index 145b4584..00000000
--- a/crates/website/src/site/routes/auth/login.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-use leptos::*;
-use leptos_router::*;
-
-use crate::auth::oauth2::finish_auth_flow;
-
-#[derive(Params, PartialEq, Clone)]
-struct QueryParams {
- state: String,
- code: String,
-}
-
-#[component]
-pub fn Login(cx: Scope) -> impl IntoView {
- let res = create_blocking_resource(
- cx,
- move || use_query::(cx).get().unwrap(),
- move |params| finish_auth_flow(cx, params.code.clone(), params.state.clone()),
- );
-
- view! { cx,
-
-
- {move || {
- res.with(
- cx,
- move |res| {
- res.clone()
- .map(move |_| {
- create_effect(
- cx,
- |_| {
- window().location().assign("/servers").unwrap();
- },
- );
- "Redirecting..."
- })
- },
- )
- }}
-
-
-
- }
- .into_view(cx)
-}
diff --git a/crates/website/src/site/routes/auth/mod.rs b/crates/website/src/site/routes/auth/mod.rs
deleted file mode 100644
index 61103062..00000000
--- a/crates/website/src/site/routes/auth/mod.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-pub mod login;
-pub mod redirect;
diff --git a/crates/website/src/site/routes/auth/redirect.rs b/crates/website/src/site/routes/auth/redirect.rs
deleted file mode 100644
index 0a52188d..00000000
--- a/crates/website/src/site/routes/auth/redirect.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use leptos::*;
-
-use crate::auth::oauth2::begin_auth_flow;
-
-#[component]
-pub fn AuthRedirect(cx: Scope) -> impl IntoView {
- let res = create_blocking_resource(cx, || (), move |_| begin_auth_flow(cx));
-
- view! { cx,
-
-
- {move || {
- res.with(
- cx,
- move |url| {
- url.clone()
- .map(|url| {
- create_effect(
- cx,
- move |_| {
- window().location().assign(&url).unwrap();
- },
- );
- view! { cx, "Redirecting..." }
- })
- },
- )
- }}
-
-
-
- }
-}
diff --git a/crates/website/src/site/routes/servers/id/mod.rs b/crates/website/src/site/routes/servers/id/mod.rs
index 0c19f9de..4d3ec7e5 100644
--- a/crates/website/src/site/routes/servers/id/mod.rs
+++ b/crates/website/src/site/routes/servers/id/mod.rs
@@ -5,7 +5,7 @@ use leptos::*;
use leptos_icons::*;
use leptos_router::*;
use serde::{Deserialize, Serialize};
-use twilight_model::{guild::Guild, id::Id};
+use twilight_model::guild::Guild;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GuildData {
@@ -17,6 +17,8 @@ pub type GuildContext = Resource, ServerFnError>>;
#[server(GetGuild, "/api")]
pub async fn get_guild(cx: Scope, id: u64) -> Result, ServerFnError> {
+ use twilight_model::id::Id;
+
let db = crate::db(cx);
let http = crate::bot_http(cx);
From 2cf9d4c6049b6fb334afbcf6bc79f6ec73eb1d46 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Sun, 6 Aug 2023 21:24:49 -0400
Subject: [PATCH 028/119] remove access token from jwt
---
crates/website/src/auth/jwt.rs | 15 ++-------------
crates/website/src/auth/oauth2.rs | 2 +-
2 files changed, 3 insertions(+), 14 deletions(-)
diff --git a/crates/website/src/auth/jwt.rs b/crates/website/src/auth/jwt.rs
index ffd89740..8c8f085f 100644
--- a/crates/website/src/auth/jwt.rs
+++ b/crates/website/src/auth/jwt.rs
@@ -1,5 +1,4 @@
use jwt_simple::prelude::*;
-use oauth2::AccessToken;
use serde::{Deserialize, Serialize};
use twilight_model::id::{marker::UserMarker, Id};
@@ -7,21 +6,11 @@ use twilight_model::id::{marker::UserMarker, Id};
pub struct AuthClaims {
/// The ID of the authenticated user.
pub user_id: Id,
- /// The oauth2 token of the authenticated user.
- ///
- /// This is stored, unencrypted, in the cookies
- /// of the clients browser. This is safe because
- /// the oauth2 tokens we generate only ever have
- /// the "identify" and "guilds" scope.
- pub user_token: AccessToken,
}
impl AuthClaims {
- pub fn new(user_id: Id, user_token: AccessToken) -> Self {
- Self {
- user_id,
- user_token,
- }
+ pub fn new(user_id: Id) -> Self {
+ Self { user_id }
}
pub fn build(self) -> JWTClaims {
diff --git a/crates/website/src/auth/oauth2.rs b/crates/website/src/auth/oauth2.rs
index eafdb0de..e30c6ac2 100644
--- a/crates/website/src/auth/oauth2.rs
+++ b/crates/website/src/auth/oauth2.rs
@@ -100,7 +100,7 @@ pub async fn finish_auth_flow(cx: leptos::Scope) -> Result<(), ServerFnError> {
let http = twilight_http::Client::new(format!("Bearer {}", token.secret()));
let user = http.current_user().await?.model().await?;
- let claims = AuthClaims::new(user.id, token).build();
+ let claims = AuthClaims::new(user.id).build();
let jwt = jwt_key.authenticate(claims.clone()).unwrap();
let acx = AuthContext { http, claims };
From 7abf11ebad21e55a6dbf3e6de7f81bbefbe145dd Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Sun, 6 Aug 2023 21:44:26 -0400
Subject: [PATCH 029/119] fix flashing navbar
---
crates/website/src/site/routes/mod.rs | 4 +++-
crates/website/src/site/routes/servers/id/mod.rs | 11 ++++++++---
.../src/site/routes/servers/server_list.rs | 15 ++++-----------
3 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index 324cc7e9..e4b82fe5 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -48,6 +48,9 @@ fn WebsiteRoutes(cx: Scope) -> impl IntoView {
view! { cx,
+
+
+
@@ -58,7 +61,6 @@ fn WebsiteRoutes(cx: Scope) -> impl IntoView {
fn DashboardRoutes(cx: Scope) -> impl IntoView {
view! { cx,
-
//
diff --git a/crates/website/src/site/routes/servers/id/mod.rs b/crates/website/src/site/routes/servers/id/mod.rs
index 4d3ec7e5..0838c45b 100644
--- a/crates/website/src/site/routes/servers/id/mod.rs
+++ b/crates/website/src/site/routes/servers/id/mod.rs
@@ -13,7 +13,7 @@ pub struct GuildData {
pub http: Guild,
}
-pub type GuildContext = Resource, ServerFnError>>;
+pub type GuildContext = Resource, Result , ServerFnError>>;
#[server(GetGuild, "/api")]
pub async fn get_guild(cx: Scope, id: u64) -> Result , ServerFnError> {
@@ -55,8 +55,13 @@ pub fn Server(cx: Scope) -> impl IntoView {
let params = use_params::(cx);
let guild: GuildContext = create_resource(
cx,
- move || params.with(|p| p.as_ref().unwrap().id),
- move |id| get_guild(cx, id),
+ move || params.with(|p| p.as_ref().ok().map(|p| p.id)),
+ move |id| async move {
+ let Some(id) = id else {
+ return Ok(None);
+ };
+ get_guild(cx, id).await
+ },
);
provide_context(cx, guild);
diff --git a/crates/website/src/site/routes/servers/server_list.rs b/crates/website/src/site/routes/servers/server_list.rs
index e62111fa..8d0590a0 100644
--- a/crates/website/src/site/routes/servers/server_list.rs
+++ b/crates/website/src/site/routes/servers/server_list.rs
@@ -7,8 +7,6 @@ use twilight_model::{
user::CurrentUserGuild,
};
-use crate::site::components::NavBar;
-
#[server(GetGuilds, "/api")]
pub async fn get_guilds(
cx: Scope,
@@ -37,14 +35,9 @@ pub fn ServerList(cx: Scope) -> impl IntoView {
let guilds = create_resource(cx, move || (), move |_| get_guilds(cx));
view! { cx,
-
-
-
-
-
- "Go to server"
-
- {move || guilds.with(cx, |d| format!("{d:?}"))}
-
+
+ "Go to server"
+
+ {move || guilds.with(cx, |d| format!("{d:?}"))}
}
}
From 7fb2e37997585cf12afe762a3089c2aa1cccf59e Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Sun, 6 Aug 2023 22:01:39 -0400
Subject: [PATCH 030/119] use dashmap instead of RwLock
---
Cargo.lock | 3 ++-
crates/common/Cargo.toml | 3 ++-
.../src/utils => common/src}/async_dash.rs | 0
.../src/utils => common/src}/dashset_lock.rs | 2 +-
crates/common/src/lib.rs | 4 +++
crates/starboard/Cargo.toml | 2 +-
crates/starboard/src/cache/cache_struct.rs | 10 +++----
crates/starboard/src/client/locks.rs | 2 +-
crates/starboard/src/utils/mod.rs | 2 --
crates/website/Cargo.toml | 19 ++-----------
crates/website/src/auth/context.rs | 27 ++++++++-----------
crates/website/src/lib.rs | 8 +++---
crates/website/src/main.rs | 6 ++---
13 files changed, 36 insertions(+), 52 deletions(-)
rename crates/{starboard/src/utils => common/src}/async_dash.rs (100%)
rename crates/{starboard/src/utils => common/src}/dashset_lock.rs (96%)
diff --git a/Cargo.lock b/Cargo.lock
index dd5a1b06..6ff45251 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -662,6 +662,7 @@ checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271"
name = "common"
version = "0.1.0"
dependencies = [
+ "dashmap",
"dotenv",
]
@@ -4942,6 +4943,7 @@ dependencies = [
"cfg-if",
"common",
"console_error_panic_hook",
+ "dashmap",
"database",
"errors",
"http",
@@ -4953,7 +4955,6 @@ dependencies = [
"leptos_router",
"oauth2",
"once_cell",
- "parking_lot 0.12.1",
"serde",
"twilight-http",
"twilight-model",
diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml
index 4f2e2fbb..a2f117b0 100644
--- a/crates/common/Cargo.toml
+++ b/crates/common/Cargo.toml
@@ -4,7 +4,8 @@ version = "0.1.0"
edition = "2021"
[dependencies]
+dashmap = { version = "5.5.0", optional = true }
dotenv = { version = "0.15.0", optional = true }
[features]
-backend = ["dep:dotenv"]
+backend = ["dep:dotenv", "dep:dashmap"]
diff --git a/crates/starboard/src/utils/async_dash.rs b/crates/common/src/async_dash.rs
similarity index 100%
rename from crates/starboard/src/utils/async_dash.rs
rename to crates/common/src/async_dash.rs
diff --git a/crates/starboard/src/utils/dashset_lock.rs b/crates/common/src/dashset_lock.rs
similarity index 96%
rename from crates/starboard/src/utils/dashset_lock.rs
rename to crates/common/src/dashset_lock.rs
index 8d0d2e78..3a3e4258 100644
--- a/crates/starboard/src/utils/dashset_lock.rs
+++ b/crates/common/src/dashset_lock.rs
@@ -2,7 +2,7 @@ use std::hash::Hash;
use dashmap::DashSet;
-use crate::utils::async_dash::AsyncDashSet;
+use crate::async_dash::AsyncDashSet;
pub struct DashSetLock
where
diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs
index e514731c..f936094a 100644
--- a/crates/common/src/lib.rs
+++ b/crates/common/src/lib.rs
@@ -1,3 +1,7 @@
#[cfg(feature = "backend")]
+pub mod async_dash;
+#[cfg(feature = "backend")]
pub mod config;
pub mod constants;
+#[cfg(feature = "backend")]
+pub mod dashset_lock;
diff --git a/crates/starboard/Cargo.toml b/crates/starboard/Cargo.toml
index 3f33cc96..c75e2a33 100644
--- a/crates/starboard/Cargo.toml
+++ b/crates/starboard/Cargo.toml
@@ -26,7 +26,7 @@ chrono = "0.4.26"
serde_json = "1.0"
# serde = "1.0.171"
emojis = "0.6.0"
-dashmap = "5.4.0"
+dashmap = "5.5.0"
regex = "1.9.1"
lazy_static = "1.4.0"
humantime = "2.1.0"
diff --git a/crates/starboard/src/cache/cache_struct.rs b/crates/starboard/src/cache/cache_struct.rs
index 054920af..304adad4 100644
--- a/crates/starboard/src/cache/cache_struct.rs
+++ b/crates/starboard/src/cache/cache_struct.rs
@@ -14,14 +14,14 @@ use twilight_model::{
},
};
-use common::constants;
+use common::{
+ async_dash::{AsyncDashMap, AsyncDashSet},
+ constants,
+};
use errors::{get_status, StarboardResult};
use crate::{
- cache::models::channel::CachedChannel,
- client::bot::StarboardBot,
- core::emoji::SimpleEmoji,
- utils::async_dash::{AsyncDashMap, AsyncDashSet},
+ cache::models::channel::CachedChannel, client::bot::StarboardBot, core::emoji::SimpleEmoji,
};
use super::{
diff --git a/crates/starboard/src/client/locks.rs b/crates/starboard/src/client/locks.rs
index 79e0eca3..3988ee1b 100644
--- a/crates/starboard/src/client/locks.rs
+++ b/crates/starboard/src/client/locks.rs
@@ -1,6 +1,6 @@
use twilight_model::id::{marker::MessageMarker, Id};
-use crate::utils::dashset_lock::DashSetLock;
+use common::dashset_lock::DashSetLock;
#[derive(Default)]
pub struct Locks {
diff --git a/crates/starboard/src/utils/mod.rs b/crates/starboard/src/utils/mod.rs
index a0e1a2b8..f42b6efc 100644
--- a/crates/starboard/src/utils/mod.rs
+++ b/crates/starboard/src/utils/mod.rs
@@ -1,6 +1,4 @@
-pub mod async_dash;
pub mod avatar;
-pub mod dashset_lock;
pub mod div_ceil;
pub mod dm;
pub mod embed;
diff --git a/crates/website/Cargo.toml b/crates/website/Cargo.toml
index cfa25475..89ab10a7 100644
--- a/crates/website/Cargo.toml
+++ b/crates/website/Cargo.toml
@@ -28,28 +28,13 @@ twilight-model = "0.15.2"
twilight-http = { version = "0.15.2", optional = true }
jwt-simple = { version = "0.11.6", optional = true }
oauth2 = { version = "4.4.1", optional = true }
-parking_lot = {version = "0.12.1", optional = true }
+dashmap = "5.5.0"
[features]
default = ["ssr", "hydrate", "csr"]
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
-ssr = [
- "database/backend",
- "common/backend",
- "dep:errors",
- "dep:actix-files",
- "dep:actix-web",
- "dep:leptos_actix",
- "dep:once_cell",
- "dep:twilight-http",
- "dep:jwt-simple",
- "dep:oauth2",
- "dep:parking_lot",
- "leptos/ssr",
- "leptos_meta/ssr",
- "leptos_router/ssr",
-]
+ssr = ["database/backend", "common/backend", "dep:errors", "dep:actix-files", "dep:actix-web", "dep:leptos_actix", "dep:once_cell", "dep:twilight-http", "dep:jwt-simple", "dep:oauth2", "leptos/ssr", "leptos_meta/ssr", "leptos_router/ssr"]
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
diff --git a/crates/website/src/auth/context.rs b/crates/website/src/auth/context.rs
index c1be1a44..5f5efb5f 100644
--- a/crates/website/src/auth/context.rs
+++ b/crates/website/src/auth/context.rs
@@ -19,9 +19,7 @@ impl AuthContext {
pub fn provide(self, cx: leptos::Scope) -> Arc {
let states = expect_auth_states(cx);
let acx = Arc::new(self);
- states
- .write()
- .insert(acx.claims.custom.user_id, acx.clone());
+ states.insert(acx.claims.custom.user_id, acx.clone());
acx
}
@@ -33,21 +31,18 @@ impl AuthContext {
};
let claims = AuthClaims::verify(session.value(), &key)?;
- let state = {
- let states = expect_auth_states(cx);
- let states = states.read();
- states.get(&claims.custom.user_id).cloned()
- };
-
- let Some(state) = state else {
- return None;
- };
+ let states = expect_auth_states(cx);
+ states.with(&claims.custom.user_id, |_, state| {
+ let Some(state) = state else {
+ return None;
+ };
- if claims.nonce != state.claims.nonce {
- return None;
- }
+ if claims.nonce != state.claims.nonce {
+ return None;
+ }
- Some(state)
+ Some(state.value().clone())
+ })
}
pub fn build_http(access_token: &str) -> Client {
diff --git a/crates/website/src/lib.rs b/crates/website/src/lib.rs
index 42334a32..de1ce65b 100644
--- a/crates/website/src/lib.rs
+++ b/crates/website/src/lib.rs
@@ -4,14 +4,14 @@ pub mod site;
pub mod utils;
#[cfg(feature = "ssr")]
-use std::{collections::HashMap, sync::Arc};
+use std::sync::Arc;
#[cfg(feature = "ssr")]
use auth::context::AuthContext;
#[cfg(feature = "ssr")]
-use jwt_simple::prelude::HS256Key;
+use common::async_dash::AsyncDashMap;
#[cfg(feature = "ssr")]
-use parking_lot::RwLock;
+use jwt_simple::prelude::HS256Key;
#[cfg(feature = "ssr")]
use twilight_http::Client;
#[cfg(feature = "ssr")]
@@ -22,7 +22,7 @@ use twilight_model::id::Id;
use wasm_bindgen::prelude::wasm_bindgen;
#[cfg(feature = "ssr")]
-pub type AuthStates = Arc, Arc>>>;
+pub type AuthStates = Arc, Arc>>;
#[cfg(feature = "ssr")]
pub fn expect_auth_states(cx: leptos::Scope) -> AuthStates {
diff --git a/crates/website/src/main.rs b/crates/website/src/main.rs
index 13b1f1e6..1c24edcc 100644
--- a/crates/website/src/main.rs
+++ b/crates/website/src/main.rs
@@ -1,14 +1,14 @@
#[cfg(feature = "ssr")]
#[actix_web::main]
async fn main() -> std::io::Result<()> {
- use std::{collections::HashMap, sync::Arc, time::Duration};
+ use std::{sync::Arc, time::Duration};
use actix_files::Files;
use actix_web::*;
+ use dashmap::DashMap;
use leptos::*;
use leptos_actix::{generate_route_list, LeptosRoutes};
use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl};
- use parking_lot::RwLock;
use twilight_http::client::Client as HttpClient;
use website::{app::*, auth::jwt, AuthStates};
@@ -28,7 +28,7 @@ async fn main() -> std::io::Result<()> {
let http = Arc::new(http.build());
let jwt_key = Arc::new(jwt::new_secret());
- let auth_states: AuthStates = Arc::new(RwLock::new(HashMap::new()));
+ let auth_states: AuthStates = Arc::new(DashMap::new().into());
HttpServer::new(move || {
let leptos_options = &conf.leptos_options;
From e942658415645e2d0cb28e372331871c2371d5ab Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Sun, 6 Aug 2023 22:50:26 -0400
Subject: [PATCH 031/119] cache user & managed guilds
---
crates/website/src/auth/context.rs | 23 ++++++++++-
crates/website/src/auth/oauth2.rs | 2 +-
crates/website/src/site/routes/mod.rs | 2 +-
crates/website/src/site/routes/servers/mod.rs | 38 +++++++++++++++++++
.../src/site/routes/servers/server_list.rs | 28 ++++----------
crates/website/style/output.css | 4 ++
6 files changed, 72 insertions(+), 25 deletions(-)
diff --git a/crates/website/src/auth/context.rs b/crates/website/src/auth/context.rs
index 5f5efb5f..df668e38 100644
--- a/crates/website/src/auth/context.rs
+++ b/crates/website/src/auth/context.rs
@@ -1,21 +1,40 @@
-use std::sync::Arc;
+use std::{
+ collections::HashMap,
+ sync::{Arc, Mutex},
+};
use actix_web::HttpRequest;
use jwt_simple::prelude::JWTClaims;
use leptos::*;
use twilight_http::Client;
+use twilight_model::{
+ id::{marker::GuildMarker, Id},
+ user::{CurrentUser, CurrentUserGuild},
+};
use crate::{expect_auth_states, jwt_key};
use super::jwt::AuthClaims;
-#[derive(Debug)]
+pub type Guilds = HashMap, CurrentUserGuild>;
+
pub struct AuthContext {
pub http: Client,
pub claims: JWTClaims,
+ pub user: CurrentUser,
+ pub guilds: Mutex>>,
}
impl AuthContext {
+ pub fn new(http: Client, claims: JWTClaims, user: CurrentUser) -> Self {
+ Self {
+ http,
+ claims,
+ user,
+ guilds: Mutex::new(None),
+ }
+ }
+
pub fn provide(self, cx: leptos::Scope) -> Arc {
let states = expect_auth_states(cx);
let acx = Arc::new(self);
diff --git a/crates/website/src/auth/oauth2.rs b/crates/website/src/auth/oauth2.rs
index e30c6ac2..585f6a17 100644
--- a/crates/website/src/auth/oauth2.rs
+++ b/crates/website/src/auth/oauth2.rs
@@ -103,7 +103,7 @@ pub async fn finish_auth_flow(cx: leptos::Scope) -> Result<(), ServerFnError> {
let claims = AuthClaims::new(user.id).build();
let jwt = jwt_key.authenticate(claims.clone()).unwrap();
- let acx = AuthContext { http, claims };
+ let acx = AuthContext::new(http, claims, user);
acx.provide(cx);
response.insert_header(SET_COOKIE, secure_cookie("SessionKey", &jwt, true));
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index e4b82fe5..9e9f0faf 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -14,7 +14,7 @@ pub async fn get_user(cx: Scope) -> Result {
return Err(ServerFnError::ServerError("Unauthorized.".to_string()));
};
- Ok(acx.http.current_user().await?.model().await?)
+ Ok(acx.user.clone())
}
pub type UserRes = Resource<(), Result>;
diff --git a/crates/website/src/site/routes/servers/mod.rs b/crates/website/src/site/routes/servers/mod.rs
index c19603a7..8f58d7e5 100644
--- a/crates/website/src/site/routes/servers/mod.rs
+++ b/crates/website/src/site/routes/servers/mod.rs
@@ -3,9 +3,47 @@ pub mod server_list;
use leptos::*;
use leptos_router::*;
+#[cfg(feature = "ssr")]
+use std::sync::Arc;
+
+#[cfg(feature = "ssr")]
+use crate::auth::context::Guilds;
use super::UserRes;
+#[cfg(feature = "ssr")]
+pub async fn get_manageable_guilds(cx: Scope) -> Option> {
+ use std::collections::HashMap;
+
+ use twilight_model::guild::Permissions;
+
+ use crate::auth::context::AuthContext;
+
+ let acx = AuthContext::get(cx)?;
+
+ if let Some(guilds) = acx.guilds.lock().unwrap().clone() {
+ return Some(guilds);
+ }
+
+ let guilds: Arc> = Arc::new(
+ acx.http
+ .current_user_guilds()
+ .await
+ .ok()?
+ .models()
+ .await
+ .ok()?
+ .into_iter()
+ .filter(|g| g.permissions.contains(Permissions::ADMINISTRATOR))
+ .map(|g| (g.id, g))
+ .collect(),
+ );
+
+ *acx.guilds.lock().unwrap() = Some(guilds.clone());
+
+ Some(guilds)
+}
+
#[component]
pub fn Servers(cx: Scope) -> impl IntoView {
let user = expect_context::(cx);
diff --git a/crates/website/src/site/routes/servers/server_list.rs b/crates/website/src/site/routes/servers/server_list.rs
index 8d0590a0..c728ff34 100644
--- a/crates/website/src/site/routes/servers/server_list.rs
+++ b/crates/website/src/site/routes/servers/server_list.rs
@@ -1,33 +1,19 @@
-use std::collections::HashMap;
-
use leptos::*;
use leptos_router::*;
-use twilight_model::{
- id::{marker::GuildMarker, Id},
- user::CurrentUserGuild,
-};
+use twilight_model::user::CurrentUserGuild;
#[server(GetGuilds, "/api")]
-pub async fn get_guilds(
- cx: Scope,
-) -> Result, CurrentUserGuild>, ServerFnError> {
- use crate::auth::context::AuthContext;
+pub async fn get_guilds(cx: Scope) -> Result, ServerFnError> {
+ use super::get_manageable_guilds;
- let Some(auth) = AuthContext::get(cx) else {
+ let Some(guilds) = get_manageable_guilds(cx).await else {
return Err(ServerFnError::ServerError("Unauthorized.".to_string()));
};
- let new_guilds: HashMap<_, _> = auth
- .http
- .current_user_guilds()
- .await?
- .models()
- .await?
- .into_iter()
- .map(|g| (g.id, g))
- .collect();
+ let mut guilds: Vec<_> = guilds.iter().map(|(_, v)| v.clone()).collect();
+ guilds.sort_by(|l, r| l.name.cmp(&r.name));
- Ok(new_guilds)
+ Ok(guilds)
}
#[component]
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
index adaa9205..de430bd7 100644
--- a/crates/website/style/output.css
+++ b/crates/website/style/output.css
@@ -1041,3 +1041,7 @@ html {
.normal-case {
text-transform: none;
}
+
+.filter {
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+}
From 029642f0571b2c4d00901e7ba9f1f9309bc6f398 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Sun, 6 Aug 2023 23:47:29 -0400
Subject: [PATCH 032/119] server list
---
crates/website/Cargo.toml | 2 +-
.../src/site/routes/servers/server_list.rs | 49 ++++-
crates/website/style/output.css | 184 ++++++++++++++++++
3 files changed, 230 insertions(+), 5 deletions(-)
diff --git a/crates/website/Cargo.toml b/crates/website/Cargo.toml
index 89ab10a7..0b7532ea 100644
--- a/crates/website/Cargo.toml
+++ b/crates/website/Cargo.toml
@@ -21,7 +21,7 @@ leptos_meta = { version = "0.4", features = ["nightly"] }
leptos_actix = { version = "0.4", optional = true }
leptos_router = { version = "0.4", features = ["nightly"] }
wasm-bindgen = "=0.2.87"
-leptos_icons = { version = "0.0.15", features = ["FaChevronLeftSolid"] }
+leptos_icons = { version = "0.0.15", features = ["FaChevronLeftSolid", "FaChevronRightSolid"] }
serde = "1.0.181"
once_cell = { version = "1.18.0", optional = true }
twilight-model = "0.15.2"
diff --git a/crates/website/src/site/routes/servers/server_list.rs b/crates/website/src/site/routes/servers/server_list.rs
index c728ff34..685cc1cd 100644
--- a/crates/website/src/site/routes/servers/server_list.rs
+++ b/crates/website/src/site/routes/servers/server_list.rs
@@ -1,4 +1,5 @@
use leptos::*;
+use leptos_icons::*;
use leptos_router::*;
use twilight_model::user::CurrentUserGuild;
@@ -18,12 +19,52 @@ pub async fn get_guilds(cx: Scope) -> Result, ServerFnErro
#[component]
pub fn ServerList(cx: Scope) -> impl IntoView {
- let guilds = create_resource(cx, move || (), move |_| get_guilds(cx));
+ let guilds = create_local_resource(cx, move || (), move |_| get_guilds(cx));
+
+ let guild_cards = move || {
+ guilds.with(cx, move |guilds| {
+ guilds.clone().map(move |guilds| {
+ view! { cx,
+ }
+ />
+ }
+ })
+ })
+ };
+ view! { cx,
+
+ }
+}
+
+#[component]
+fn ServerCard(cx: Scope, guild: CurrentUserGuild) -> impl IntoView {
+ let icon_url = guild
+ .icon
+ .map(|icon| format!("https://cdn.discordapp.com/icons/{}/{}.png", guild.id, icon));
view! { cx,
-
- "Go to server"
+
+
+ {icon_url
+ .map(|url| {
+ view! { cx,
+
+
+
+
+
+ }
+ })}
+ {guild.name}
+
+
- {move || guilds.with(cx, |d| format!("{d:?}"))}
}
}
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
index de430bd7..9a5b963f 100644
--- a/crates/website/style/output.css
+++ b/crates/website/style/output.css
@@ -581,6 +581,30 @@ html {
--tw-backdrop-sepia: ;
}
+.avatar {
+ position: relative;
+ display: inline-flex;
+}
+
+.avatar > div {
+ display: block;
+ aspect-ratio: 1 / 1;
+ overflow: hidden;
+}
+
+.avatar img {
+ height: 100%;
+ width: 100%;
+ -o-object-fit: cover;
+ object-fit: cover;
+}
+
+.avatar.placeholder > div {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
.btn {
display: inline-flex;
flex-shrink: 0;
@@ -723,6 +747,15 @@ html {
text-decoration-line: underline;
}
+.mask {
+ -webkit-mask-size: contain;
+ mask-size: contain;
+ -webkit-mask-repeat: no-repeat;
+ mask-repeat: no-repeat;
+ -webkit-mask-position: center;
+ mask-position: center;
+}
+
.navbar {
display: flex;
align-items: center;
@@ -736,6 +769,14 @@ html {
align-items: center;
}
+.avatar-group :where(.avatar) {
+ overflow: hidden;
+ border-radius: 9999px;
+ border-width: 4px;
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--b1) / var(--tw-border-opacity));
+}
+
.btn:active:hover,
.btn:active:focus {
animation: button-pop 0s ease-out;
@@ -886,6 +927,11 @@ html {
outline-offset: 2px;
}
+.mask-squircle {
+ -webkit-mask-image: url("data:image/svg+xml,%3csvg width='200' height='200' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M100 0C20 0 0 20 0 100s20 100 100 100 100-20 100-100S180 0 100 0Z'/%3e%3c/svg%3e");
+ mask-image: url("data:image/svg+xml,%3csvg width='200' height='200' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M100 0C20 0 0 20 0 100s20 100 100 100 100-20 100-100S180 0 100 0Z'/%3e%3c/svg%3e");
+}
+
@keyframes modal-pop {
0% {
opacity: 0;
@@ -946,12 +992,30 @@ html {
font-size: 0.875rem;
}
+.btn-lg {
+ height: 4rem;
+ padding-left: 1.5rem;
+ padding-right: 1.5rem;
+ min-height: 4rem;
+ font-size: 1.125rem;
+}
+
+.btn-block {
+ width: 100%;
+}
+
.btn-square:where(.btn-sm) {
height: 2rem;
width: 2rem;
padding: 0px;
}
+.btn-square:where(.btn-lg) {
+ height: 4rem;
+ width: 4rem;
+ padding: 0px;
+}
+
.btn-circle:where(.btn-sm) {
height: 2rem;
width: 2rem;
@@ -959,6 +1023,47 @@ html {
padding: 0px;
}
+.btn-circle:where(.btn-lg) {
+ height: 4rem;
+ width: 4rem;
+ border-radius: 9999px;
+ padding: 0px;
+}
+
+.avatar.online:before {
+ content: "";
+ position: absolute;
+ z-index: 10;
+ display: block;
+ border-radius: 9999px;
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--su) / var(--tw-bg-opacity));
+ outline-style: solid;
+ outline-width: 2px;
+ outline-color: hsl(var(--b1) / 1);
+ width: 15%;
+ height: 15%;
+ top: 7%;
+ right: 7%;
+}
+
+.avatar.offline:before {
+ content: "";
+ position: absolute;
+ z-index: 10;
+ display: block;
+ border-radius: 9999px;
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b3) / var(--tw-bg-opacity));
+ outline-style: solid;
+ outline-width: 2px;
+ outline-color: hsl(var(--b1) / 1);
+ width: 15%;
+ height: 15%;
+ top: 7%;
+ right: 7%;
+}
+
.btn-group .btn:not(:first-child):not(:last-child) {
border-top-left-radius: 0;
border-top-right-radius: 0;
@@ -1021,18 +1126,97 @@ html {
border-bottom-right-radius: var(--rounded-btn, 0.5rem);
}
+.m-20 {
+ margin: 5rem;
+}
+
+.m-5 {
+ margin: 1.25rem;
+}
+
+.m-12 {
+ margin: 3rem;
+}
+
+.my-5 {
+ margin-top: 1.25rem;
+ margin-bottom: 1.25rem;
+}
+
+.my-2 {
+ margin-top: 0.5rem;
+ margin-bottom: 0.5rem;
+}
+
+.mt-0 {
+ margin-top: 0px;
+}
+
.inline {
display: inline;
}
+.flex {
+ display: flex;
+}
+
+.w-full {
+ width: 100%;
+}
+
+.w-24 {
+ width: 6rem;
+}
+
+.w-5 {
+ width: 1.25rem;
+}
+
+.w-12 {
+ width: 3rem;
+}
+
+.max-w-lg {
+ max-width: 32rem;
+}
+
+.max-w-4xl {
+ max-width: 56rem;
+}
+
.flex-1 {
flex: 1 1 0%;
}
+.flex-row {
+ flex-direction: row;
+}
+
+.justify-start {
+ justify-content: flex-start;
+}
+
.justify-center {
justify-content: center;
}
+.p-20 {
+ padding: 5rem;
+}
+
+.p-5 {
+ padding: 1.25rem;
+}
+
+.py-5 {
+ padding-top: 1.25rem;
+ padding-bottom: 1.25rem;
+}
+
+.text-left {
+ text-align: left;
+}
+
.text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
From e3df9f4570334e52a1eb7a6ae53e7d218341a498 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Mon, 7 Aug 2023 00:27:43 -0400
Subject: [PATCH 033/119] suspense skeleton for server list
---
.../src/site/routes/servers/server_list.rs | 41 ++++-
crates/website/style/output.css | 157 ++++++++++++++++++
2 files changed, 194 insertions(+), 4 deletions(-)
diff --git a/crates/website/src/site/routes/servers/server_list.rs b/crates/website/src/site/routes/servers/server_list.rs
index 685cc1cd..cca69392 100644
--- a/crates/website/src/site/routes/servers/server_list.rs
+++ b/crates/website/src/site/routes/servers/server_list.rs
@@ -34,15 +34,39 @@ pub fn ServerList(cx: Scope) -> impl IntoView {
})
})
};
+ let susp = move || {
+ view! { cx,
+ }
+ />
+ }
+ };
view! { cx,
- {guild_cards}
+ {guild_cards}
}
}
+#[component]
+fn ServerCardSkeleton(cx: Scope) -> impl IntoView {
+ view! { cx,
+
+
+
+
+
+ }
+}
+
#[component]
fn ServerCard(cx: Scope, guild: CurrentUserGuild) -> impl IntoView {
let icon_url = guild
@@ -52,8 +76,8 @@ fn ServerCard(cx: Scope, guild: CurrentUserGuild) -> impl IntoView {
view! { cx,
- {icon_url
- .map(|url| {
+ {match icon_url {
+ Some(url) => {
view! { cx,
@@ -61,7 +85,16 @@ fn ServerCard(cx: Scope, guild: CurrentUserGuild) -> impl IntoView {
}
- })}
+ }
+ None => {
+
+ view! { cx,
+
+ }
+ }
+ }}
{guild.name}
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
index 9a5b963f..5de576b5 100644
--- a/crates/website/style/output.css
+++ b/crates/website/style/output.css
@@ -677,6 +677,16 @@ html {
}
@media (hover: hover) {
+ .btm-nav > *.disabled:hover,
+ .btm-nav > *[disabled]:hover {
+ pointer-events: none;
+ --tw-border-opacity: 0;
+ background-color: hsl(var(--n) / var(--tw-bg-opacity));
+ --tw-bg-opacity: 0.1;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ --tw-text-opacity: 0.2;
+ }
+
.btn:hover {
--tw-border-opacity: 1;
border-color: hsl(var(--b3) / var(--tw-border-opacity));
@@ -727,6 +737,15 @@ html {
--tw-bg-opacity: 1;
background-color: hsl(var(--pf) / var(--tw-bg-opacity));
}
+
+ :where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):not(.active):hover, :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):not(.active):hover {
+ cursor: pointer;
+ background-color: hsl(var(--bc) / 0.1);
+ --tw-text-opacity: 1;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+ }
}
.hero {
@@ -756,6 +775,14 @@ html {
mask-position: center;
}
+.menu li.disabled {
+ cursor: not-allowed;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+ color: hsl(var(--bc) / 0.3);
+}
+
.navbar {
display: flex;
align-items: center;
@@ -777,6 +804,16 @@ html {
border-color: hsl(var(--b1) / var(--tw-border-opacity));
}
+.btm-nav > *.disabled,
+ .btm-nav > *[disabled] {
+ pointer-events: none;
+ --tw-border-opacity: 0;
+ background-color: hsl(var(--n) / var(--tw-bg-opacity));
+ --tw-bg-opacity: 0.1;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ --tw-text-opacity: 0.2;
+}
+
.btn:active:hover,
.btn:active:focus {
animation: button-pop 0s ease-out;
@@ -1152,6 +1189,14 @@ html {
margin-top: 0px;
}
+.mb-2 {
+ margin-bottom: 0.5rem;
+}
+
+.mb-2\.5 {
+ margin-bottom: 0.625rem;
+}
+
.inline {
display: inline;
}
@@ -1160,6 +1205,19 @@ html {
display: flex;
}
+.h-2 {
+ height: 0.5rem;
+}
+
+.h-max {
+ height: -moz-max-content;
+ height: max-content;
+}
+
+.h-5 {
+ height: 1.25rem;
+}
+
.w-full {
width: 100%;
}
@@ -1176,6 +1234,19 @@ html {
width: 3rem;
}
+.w-\[360px\] {
+ width: 360px;
+}
+
+.w-max {
+ width: -moz-max-content;
+ width: max-content;
+}
+
+.w-\[400px\] {
+ width: 400px;
+}
+
.max-w-lg {
max-width: 32rem;
}
@@ -1184,14 +1255,32 @@ html {
max-width: 56rem;
}
+.max-w-\[360px\] {
+ max-width: 360px;
+}
+
.flex-1 {
flex: 1 1 0%;
}
+@keyframes pulse {
+ 50% {
+ opacity: .5;
+ }
+}
+
+.animate-pulse {
+ animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
+}
+
.flex-row {
flex-direction: row;
}
+.content-start {
+ align-content: flex-start;
+}
+
.justify-start {
justify-content: flex-start;
}
@@ -1200,6 +1289,66 @@ html {
justify-content: center;
}
+.rounded-full {
+ border-radius: 9999px;
+}
+
+.bg-slate-500 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(100 116 139 / var(--tw-bg-opacity));
+}
+
+.bg-gray-700 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(55 65 81 / var(--tw-bg-opacity));
+}
+
+.bg-gray-50 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(249 250 251 / var(--tw-bg-opacity));
+}
+
+.bg-gray-400 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(156 163 175 / var(--tw-bg-opacity));
+}
+
+.bg-transparent {
+ background-color: transparent;
+}
+
+.bg-gray-500 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(107 114 128 / var(--tw-bg-opacity));
+}
+
+.\!bg-transparent {
+ background-color: transparent !important;
+}
+
+.bg-gray-600 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(75 85 99 / var(--tw-bg-opacity));
+}
+
+.bg-gray-800 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(31 41 55 / var(--tw-bg-opacity));
+}
+
+.bg-gray-300 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(209 213 219 / var(--tw-bg-opacity));
+}
+
+.bg-opacity-10 {
+ --tw-bg-opacity: 0.1;
+}
+
+.bg-opacity-30 {
+ --tw-bg-opacity: 0.3;
+}
+
.p-20 {
padding: 5rem;
}
@@ -1226,6 +1375,14 @@ html {
text-transform: none;
}
+.opacity-0 {
+ opacity: 0;
+}
+
.filter {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
+
+.hover\:bg-transparent:hover {
+ background-color: transparent;
+}
From 6395fdab2a1f69a8e7e3b9d34b17de30c5d501de Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Mon, 7 Aug 2023 12:22:14 -0400
Subject: [PATCH 034/119] toasts for errors
---
Cargo.lock | 4 +
crates/website/Cargo.toml | 3 +-
crates/website/src/site/components/mod.rs | 2 +
.../src/site/components/toasted_susp.rs | 149 ++++++++++++++++
crates/website/src/site/routes/mod.rs | 18 +-
.../src/site/routes/servers/server_list.rs | 3 +-
crates/website/style/output.css | 166 ++++++++++++++++++
7 files changed, 336 insertions(+), 9 deletions(-)
create mode 100644 crates/website/src/site/components/toasted_susp.rs
diff --git a/Cargo.lock b/Cargo.lock
index 6ff45251..aba6481e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1913,6 +1913,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
]
[[package]]
@@ -4947,6 +4950,7 @@ dependencies = [
"database",
"errors",
"http",
+ "instant",
"jwt-simple",
"leptos",
"leptos_actix",
diff --git a/crates/website/Cargo.toml b/crates/website/Cargo.toml
index 0b7532ea..b52d30a5 100644
--- a/crates/website/Cargo.toml
+++ b/crates/website/Cargo.toml
@@ -21,7 +21,7 @@ leptos_meta = { version = "0.4", features = ["nightly"] }
leptos_actix = { version = "0.4", optional = true }
leptos_router = { version = "0.4", features = ["nightly"] }
wasm-bindgen = "=0.2.87"
-leptos_icons = { version = "0.0.15", features = ["FaChevronLeftSolid", "FaChevronRightSolid"] }
+leptos_icons = { version = "0.0.15", features = ["FaChevronLeftSolid", "FaChevronRightSolid", "FaXmarkSolid"] }
serde = "1.0.181"
once_cell = { version = "1.18.0", optional = true }
twilight-model = "0.15.2"
@@ -29,6 +29,7 @@ twilight-http = { version = "0.15.2", optional = true }
jwt-simple = { version = "0.11.6", optional = true }
oauth2 = { version = "4.4.1", optional = true }
dashmap = "5.5.0"
+instant = { version = "0.1.12", features=["wasm-bindgen", "inaccurate"] }
[features]
default = ["ssr", "hydrate", "csr"]
diff --git a/crates/website/src/site/components/mod.rs b/crates/website/src/site/components/mod.rs
index 7b062f5c..5ea15cfe 100644
--- a/crates/website/src/site/components/mod.rs
+++ b/crates/website/src/site/components/mod.rs
@@ -1,3 +1,5 @@
mod navbar;
+mod toasted_susp;
pub use navbar::NavBar;
+pub use toasted_susp::{toast, Toast, ToastCx, ToastProvider, ToastedSusp};
diff --git a/crates/website/src/site/components/toasted_susp.rs b/crates/website/src/site/components/toasted_susp.rs
new file mode 100644
index 00000000..93fe83a8
--- /dev/null
+++ b/crates/website/src/site/components/toasted_susp.rs
@@ -0,0 +1,149 @@
+use std::time::Duration;
+
+use instant::Instant;
+use leptos::*;
+use leptos_icons::*;
+
+#[derive(Clone, Copy)]
+pub enum ToastType {
+ Error,
+ Warning,
+ Info,
+ Success,
+}
+
+impl ToastType {
+ pub fn as_class(&self) -> &'static str {
+ match self {
+ Self::Error => "alert-error",
+ Self::Warning => "alert-warning",
+ Self::Info => "alert-info",
+ Self::Success => "alert-success",
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct Toast {
+ pub typ: ToastType,
+ pub msg: String,
+ pub ts: Instant,
+ pub lifespan: Duration,
+}
+
+impl Toast {
+ pub fn error(msg: impl ToString) -> Self {
+ Self {
+ typ: ToastType::Error,
+ msg: msg.to_string(),
+ ts: Instant::now(),
+ lifespan: Duration::from_secs(5),
+ }
+ }
+
+ pub fn warning(msg: impl ToString) -> Self {
+ Self {
+ typ: ToastType::Warning,
+ msg: msg.to_string(),
+ ts: Instant::now(),
+ lifespan: Duration::from_secs(5),
+ }
+ }
+
+ pub fn info(msg: impl ToString) -> Self {
+ Self {
+ typ: ToastType::Info,
+ msg: msg.to_string(),
+ ts: Instant::now(),
+ lifespan: Duration::from_secs(5),
+ }
+ }
+
+ pub fn success(msg: impl ToString) -> Self {
+ Self {
+ typ: ToastType::Info,
+ msg: msg.to_string(),
+ ts: Instant::now(),
+ lifespan: Duration::from_secs(5),
+ }
+ }
+}
+
+pub type ToastCx = RwSignal>;
+
+pub fn toast(cx: Scope, toast: Toast) {
+ let lifespan = toast.lifespan;
+ let ts = toast.ts;
+ let toasts = expect_context::(cx);
+
+ toasts.update(|toasts| {
+ toasts.push(toast);
+ });
+
+ create_effect(cx, move |_| {
+ set_timeout(
+ move || {
+ toasts.try_update(|toasts| {
+ toasts.retain(|t| t.ts != ts);
+ });
+ },
+ lifespan,
+ )
+ });
+}
+
+#[component]
+pub fn ToastProvider(cx: Scope, children: Children) -> impl IntoView {
+ let toasts: ToastCx = create_rw_signal(cx, Vec::::new());
+ provide_context(cx, toasts);
+
+ let close = move |ts: Instant| {
+ toasts.update(|toasts| toasts.retain(|t| t.ts != ts));
+ };
+
+ view! { cx,
+
+
+ {t.with_value(|t| t.msg.clone())}
+
+
+
+
+ }
+ }
+ />
+
+
+ {children(cx)}
+ }
+}
+
+#[component(transparent)]
+pub fn ToastedSusp
(cx: Scope, fallback: F, children: ChildrenFn) -> impl IntoView
+where
+ F: Fn() -> FIV + 'static,
+ FIV: IntoView,
+{
+ let children = store_value(cx, children);
+ let fallback = store_value(cx, fallback);
+
+ view! { cx,
+
+ {children.with_value(|c| c(cx))}
+
+ }
+}
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index 9e9f0faf..8bc5f97d 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -5,6 +5,8 @@ use leptos::*;
use leptos_router::*;
use twilight_model::user::CurrentUser;
+use crate::site::components::ToastProvider;
+
use super::errors;
#[server(GetUser, "/api")]
@@ -25,14 +27,16 @@ pub fn Index(cx: Scope) -> impl IntoView {
provide_context(cx, user);
view! { cx,
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
+
}
}
diff --git a/crates/website/src/site/routes/servers/server_list.rs b/crates/website/src/site/routes/servers/server_list.rs
index cca69392..8d3a51e3 100644
--- a/crates/website/src/site/routes/servers/server_list.rs
+++ b/crates/website/src/site/routes/servers/server_list.rs
@@ -1,3 +1,4 @@
+use crate::site::components::ToastedSusp;
use leptos::*;
use leptos_icons::*;
use leptos_router::*;
@@ -46,7 +47,7 @@ pub fn ServerList(cx: Scope) -> impl IntoView {
view! { cx,
- {guild_cards}
+ {guild_cards}
}
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
index 5de576b5..2dc11caa 100644
--- a/crates/website/style/output.css
+++ b/crates/website/style/output.css
@@ -581,6 +581,36 @@ html {
--tw-backdrop-sepia: ;
}
+.alert {
+ display: grid;
+ width: 100%;
+ grid-auto-flow: row;
+ align-content: flex-start;
+ align-items: center;
+ justify-items: center;
+ gap: 1rem;
+ text-align: center;
+ border-width: 1px;
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--b2) / var(--tw-border-opacity));
+ padding: 1rem;
+ --tw-text-opacity: 1;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ border-radius: var(--rounded-box, 1rem);
+ --alert-bg: hsl(var(--b2));
+ --alert-bg-mix: hsl(var(--b1));
+ background-color: var(--alert-bg);
+}
+
+@media (min-width: 640px) {
+ .alert {
+ grid-auto-flow: column;
+ grid-template-columns: auto minmax(auto,1fr);
+ justify-items: start;
+ text-align: left;
+ }
+}
+
.avatar {
position: relative;
display: inline-flex;
@@ -652,6 +682,13 @@ html {
pointer-events: none;
}
+.btn-circle {
+ height: 3rem;
+ width: 3rem;
+ border-radius: 9999px;
+ padding: 0px;
+}
+
.btn-group > input[type="radio"].btn {
-webkit-appearance: none;
-moz-appearance: none;
@@ -796,6 +833,49 @@ html {
align-items: center;
}
+.toast {
+ position: fixed;
+ display: flex;
+ min-width: -moz-fit-content;
+ min-width: fit-content;
+ flex-direction: column;
+ white-space: nowrap;
+ gap: 0.5rem;
+ padding: 1rem;
+}
+
+.alert-info {
+ border-color: hsl(var(--in) / 0.2);
+ --tw-text-opacity: 1;
+ color: hsl(var(--inc) / var(--tw-text-opacity));
+ --alert-bg: hsl(var(--in));
+ --alert-bg-mix: hsl(var(--b1));
+}
+
+.alert-success {
+ border-color: hsl(var(--su) / 0.2);
+ --tw-text-opacity: 1;
+ color: hsl(var(--suc) / var(--tw-text-opacity));
+ --alert-bg: hsl(var(--su));
+ --alert-bg-mix: hsl(var(--b1));
+}
+
+.alert-warning {
+ border-color: hsl(var(--wa) / 0.2);
+ --tw-text-opacity: 1;
+ color: hsl(var(--wac) / var(--tw-text-opacity));
+ --alert-bg: hsl(var(--wa));
+ --alert-bg-mix: hsl(var(--b1));
+}
+
+.alert-error {
+ border-color: hsl(var(--er) / 0.2);
+ --tw-text-opacity: 1;
+ color: hsl(var(--erc) / var(--tw-text-opacity));
+ --alert-bg: hsl(var(--er));
+ --alert-bg-mix: hsl(var(--b1));
+}
+
.avatar-group :where(.avatar) {
overflow: hidden;
border-radius: 9999px;
@@ -1009,6 +1089,10 @@ html {
}
}
+.toast > * {
+ animation: toast-pop 0.25s ease-out;
+}
+
@keyframes toast-pop {
0% {
transform: scale(0.9);
@@ -1053,6 +1137,13 @@ html {
padding: 0px;
}
+.btn-circle:where(.btn-xs) {
+ height: 1.5rem;
+ width: 1.5rem;
+ border-radius: 9999px;
+ padding: 0px;
+}
+
.btn-circle:where(.btn-sm) {
height: 2rem;
width: 2rem;
@@ -1060,6 +1151,13 @@ html {
padding: 0px;
}
+.btn-circle:where(.btn-md) {
+ height: 3rem;
+ width: 3rem;
+ border-radius: 9999px;
+ padding: 0px;
+}
+
.btn-circle:where(.btn-lg) {
height: 4rem;
width: 4rem;
@@ -1067,6 +1165,58 @@ html {
padding: 0px;
}
+:where(.toast) {
+ right: 0px;
+ left: auto;
+ top: auto;
+ bottom: 0px;
+ --tw-translate-x: 0px;
+ --tw-translate-y: 0px;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.toast:where(.toast-start) {
+ right: auto;
+ left: 0px;
+ --tw-translate-x: 0px;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.toast:where(.toast-center) {
+ right: 50%;
+ left: 50%;
+ --tw-translate-x: -50%;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.toast:where(.toast-end) {
+ right: 0px;
+ left: auto;
+ --tw-translate-x: 0px;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.toast:where(.toast-bottom) {
+ top: auto;
+ bottom: 0px;
+ --tw-translate-y: 0px;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.toast:where(.toast-middle) {
+ top: 50%;
+ bottom: auto;
+ --tw-translate-y: -50%;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.toast:where(.toast-top) {
+ top: 0px;
+ bottom: auto;
+ --tw-translate-y: 0px;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
.avatar.online:before {
content: "";
position: absolute;
@@ -1163,6 +1313,14 @@ html {
border-bottom-right-radius: var(--rounded-btn, 0.5rem);
}
+.static {
+ position: static;
+}
+
+.z-50 {
+ z-index: 50;
+}
+
.m-20 {
margin: 5rem;
}
@@ -1218,6 +1376,10 @@ html {
height: 1.25rem;
}
+.h-6 {
+ height: 1.5rem;
+}
+
.w-full {
width: 100%;
}
@@ -1247,6 +1409,10 @@ html {
width: 400px;
}
+.w-6 {
+ width: 1.5rem;
+}
+
.max-w-lg {
max-width: 32rem;
}
From 67d168e411505fad5478fd14413f933fa68e5cff Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Mon, 7 Aug 2023 15:52:12 -0400
Subject: [PATCH 035/119] skeleton dashboard
---
crates/website/src/site/routes/mod.rs | 4 +-
.../website/src/site/routes/servers/id/mod.rs | 24 +-
.../src/site/routes/servers/id/overview.rs | 12 +-
.../src/site/routes/servers/id/sidebar.rs | 93 ++
.../site/routes/servers/id/starboards/mod.rs | 6 +
crates/website/style/output.css | 894 ++++++++++++++++++
6 files changed, 1022 insertions(+), 11 deletions(-)
create mode 100644 crates/website/src/site/routes/servers/id/sidebar.rs
create mode 100644 crates/website/src/site/routes/servers/id/starboards/mod.rs
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index 8bc5f97d..2762acbe 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -67,9 +67,7 @@ fn DashboardRoutes(cx: Scope) -> impl IntoView {
- //
- //
- //
+
diff --git a/crates/website/src/site/routes/servers/id/mod.rs b/crates/website/src/site/routes/servers/id/mod.rs
index 0838c45b..c7bd6394 100644
--- a/crates/website/src/site/routes/servers/id/mod.rs
+++ b/crates/website/src/site/routes/servers/id/mod.rs
@@ -1,4 +1,8 @@
pub mod overview;
+mod sidebar;
+pub mod starboards;
+
+use sidebar::{SideBar, Tab};
use database::DbGuild;
use leptos::*;
@@ -52,6 +56,7 @@ struct Props {
#[component]
pub fn Server(cx: Scope) -> impl IntoView {
+ let location = use_location(cx);
let params = use_params::(cx);
let guild: GuildContext = create_resource(
cx,
@@ -78,14 +83,21 @@ pub fn Server(cx: Scope) -> impl IntoView {
})
};
+ let tab = create_memo(cx, move |_| {
+ match location.pathname.get().split('/').last().unwrap_or("") {
+ "starboards" => Tab::Starboards,
+ "overrides" => Tab::Overrides,
+ "filters" => Tab::Filters,
+ "permroles" => Tab::PermRoles,
+ "awardroles" => Tab::AwardRoles,
+ "autostar" => Tab::AutoStar,
+ _ => Tab::Overview,
+ }
+ });
+
view! { cx,
{red}
-
-
-
-
-
-
+
}
}
diff --git a/crates/website/src/site/routes/servers/id/overview.rs b/crates/website/src/site/routes/servers/id/overview.rs
index 8986f8b3..b0d3e1d0 100644
--- a/crates/website/src/site/routes/servers/id/overview.rs
+++ b/crates/website/src/site/routes/servers/id/overview.rs
@@ -1,9 +1,17 @@
use leptos::*;
+use crate::site::components::ToastedSusp;
+
#[component]
pub fn Overview(cx: Scope) -> impl IntoView {
let guild = expect_context::(cx);
- let content = move || guild.with(cx, |g| format!("{g:?}"));
- view! { cx, {content} }
+ let content = move || {
+ guild.with(cx, |g| {
+ g.as_ref()
+ .map(|g| format!("{g:?}"))
+ .map_err(|e| e.to_owned())
+ })
+ };
+ view! { cx, {content} }
}
diff --git a/crates/website/src/site/routes/servers/id/sidebar.rs b/crates/website/src/site/routes/servers/id/sidebar.rs
new file mode 100644
index 00000000..09ff9800
--- /dev/null
+++ b/crates/website/src/site/routes/servers/id/sidebar.rs
@@ -0,0 +1,93 @@
+use leptos::*;
+use leptos_icons::*;
+use leptos_router::*;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Tab {
+ Overview,
+ Starboards,
+ Overrides,
+ Filters,
+ PermRoles,
+ AwardRoles,
+ AutoStar,
+}
+
+#[component]
+pub fn SideBar(cx: Scope, active: Memo) -> impl IntoView {
+ let guild = expect_context::(cx);
+
+ let title = move || {
+ guild.with(cx, |g| {
+ g.as_ref()
+ .ok()
+ .and_then(|g| g.as_ref())
+ .map(|g| g.http.name.to_owned())
+ })
+ };
+
+ let maybe_active = move |tab: Tab| if tab == active.get() { "active" } else { "" };
+
+ view! { cx,
+
+
+
+
+ "Open drawer"
+
+
+
+
+
+
+
+
+
+
+ }
+}
diff --git a/crates/website/src/site/routes/servers/id/starboards/mod.rs b/crates/website/src/site/routes/servers/id/starboards/mod.rs
new file mode 100644
index 00000000..8c17f9da
--- /dev/null
+++ b/crates/website/src/site/routes/servers/id/starboards/mod.rs
@@ -0,0 +1,6 @@
+use leptos::*;
+
+#[component]
+pub fn Starboards(cx: Scope) -> impl IntoView {
+ view! { cx, "Starboards" }
+}
diff --git a/crates/website/style/output.css b/crates/website/style/output.css
index 2dc11caa..e98a8bd9 100644
--- a/crates/website/style/output.css
+++ b/crates/website/style/output.css
@@ -635,6 +635,26 @@ html {
justify-content: center;
}
+@media (hover:hover) {
+ .label a:hover {
+ --tw-text-opacity: 1;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ }
+
+ .menu li > *:not(ul):not(.menu-title):not(details):active,
+.menu li > *:not(ul):not(.menu-title):not(details).active,
+.menu li > details > summary:active {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--n) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--nc) / var(--tw-text-opacity));
+ }
+
+ .tab:hover {
+ --tw-text-opacity: 1;
+ }
+}
+
.btn {
display: inline-flex;
flex-shrink: 0;
@@ -713,6 +733,147 @@ html {
content: var(--tw-content);
}
+.checkbox {
+ flex-shrink: 0;
+ --chkbg: var(--bc);
+ --chkfg: var(--b1);
+ height: 1.5rem;
+ width: 1.5rem;
+ cursor: pointer;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ border-width: 1px;
+ border-color: hsl(var(--bc) / var(--tw-border-opacity));
+ --tw-border-opacity: 0.2;
+ border-radius: var(--rounded-btn, 0.5rem);
+}
+
+.divider {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ align-self: stretch;
+ margin-top: 1rem;
+ margin-bottom: 1rem;
+ height: 1rem;
+ white-space: nowrap;
+}
+
+.divider:before,
+ .divider:after {
+ content: "";
+ flex-grow: 1;
+ height: 0.125rem;
+ width: 100%;
+}
+
+.drawer {
+ position: relative;
+ display: grid;
+ grid-auto-columns: max-content auto;
+ width: 100%;
+}
+
+.drawer-content {
+ grid-column-start: 2;
+ grid-row-start: 1;
+}
+
+.drawer-side {
+ pointer-events: none;
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ grid-column-start: 1;
+ grid-row-start: 1;
+ display: grid;
+ width: 100%;
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+ grid-template-rows: repeat(1, minmax(0, 1fr));
+ align-items: flex-start;
+ justify-items: start;
+ overflow-y: auto;
+ overscroll-behavior: contain;
+ height: 100vh;
+ height: 100dvh;
+ scrollbar-width: none;
+}
+
+.drawer-side::-webkit-scrollbar {
+ display: none;
+}
+
+.drawer-side > .drawer-overlay {
+ position: sticky;
+ top: 0px;
+ place-self: stretch;
+ cursor: pointer;
+ background-color: transparent;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ transition-duration: 200ms;
+}
+
+.drawer-side > * {
+ grid-column-start: 1;
+ grid-row-start: 1;
+}
+
+.drawer-side > *:not(.drawer-overlay) {
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ transition-duration: 300ms;
+ transform: translateX(-100%);
+}
+
+[dir="rtl"] .drawer-side > *:not(.drawer-overlay) {
+ transform: translateX(100%);
+}
+
+.drawer-toggle {
+ position: fixed;
+ height: 0px;
+ width: 0px;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ opacity: 0;
+}
+
+.drawer-toggle:checked ~ .drawer-side {
+ pointer-events: auto;
+ visibility: visible;
+}
+
+.drawer-toggle:checked ~ .drawer-side > *:not(.drawer-overlay) {
+ transform: translateX(0%);
+}
+
+.drawer-end .drawer-toggle ~ .drawer-content {
+ grid-column-start: 1;
+}
+
+.drawer-end .drawer-toggle ~ .drawer-side {
+ justify-items: end;
+}
+
+.drawer-end .drawer-toggle ~ .drawer-side > *:not(.drawer-overlay) {
+ transform: translateX(100%);
+}
+
+[dir="rtl"] .drawer-end .drawer-toggle ~ .drawer-side > *:not(.drawer-overlay) {
+ transform: translateX(-100%);
+}
+
+.drawer-end .drawer-toggle:checked ~ .drawer-side > *:not(.drawer-overlay) {
+ transform: translateX(0%);
+}
+
@media (hover: hover) {
.btm-nav > *.disabled:hover,
.btm-nav > *[disabled]:hover {
@@ -783,6 +944,26 @@ html {
outline: 2px solid transparent;
outline-offset: 2px;
}
+
+ .tab[disabled],
+ .tab[disabled]:hover {
+ cursor: not-allowed;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ --tw-text-opacity: 0.2;
+ }
+}
+
+.label {
+ display: flex;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+ align-items: center;
+ justify-content: space-between;
+ padding-left: 0.25rem;
+ padding-right: 0.25rem;
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
}
.hero {
@@ -798,6 +979,33 @@ html {
grid-row-start: 1;
}
+.input {
+ flex-shrink: 1;
+ height: 3rem;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ font-size: 1rem;
+ line-height: 2;
+ line-height: 1.5rem;
+ border-width: 1px;
+ border-color: hsl(var(--bc) / var(--tw-border-opacity));
+ --tw-border-opacity: 0;
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b1) / var(--tw-bg-opacity));
+ border-radius: var(--rounded-btn, 0.5rem);
+}
+
+.input-group > .input {
+ isolation: isolate;
+}
+
+.input-group > *,
+ .input-group > .input,
+ .input-group > .textarea,
+ .input-group > .select {
+ border-radius: 0px;
+}
+
.link {
cursor: pointer;
text-decoration-line: underline;
@@ -812,6 +1020,35 @@ html {
mask-position: center;
}
+.menu {
+ display: flex;
+ flex-direction: column;
+ flex-wrap: wrap;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ padding: 0.5rem;
+}
+
+.menu :where(li ul) {
+ position: relative;
+ white-space: nowrap;
+ margin-left: 1rem;
+ padding-left: 0.5rem;
+}
+
+.menu :where(li:not(.menu-title) > *:not(ul):not(details):not(.menu-title)),
+ .menu :where(li:not(.menu-title) > details > summary:not(.menu-title)) {
+ display: grid;
+ grid-auto-flow: column;
+ align-content: flex-start;
+ align-items: center;
+ gap: 0.5rem;
+ grid-auto-columns: minmax(auto, max-content) auto max-content;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+}
+
.menu li.disabled {
cursor: not-allowed;
-webkit-user-select: none;
@@ -820,6 +1057,23 @@ html {
color: hsl(var(--bc) / 0.3);
}
+.menu :where(li > .menu-dropdown:not(.menu-dropdown-show)) {
+ display: none;
+}
+
+:where(.menu li) {
+ position: relative;
+ display: flex;
+ flex-shrink: 0;
+ flex-direction: column;
+ flex-wrap: wrap;
+ align-items: stretch;
+}
+
+:where(.menu li) .badge {
+ justify-self: end;
+}
+
.navbar {
display: flex;
align-items: center;
@@ -833,6 +1087,31 @@ html {
align-items: center;
}
+.tab {
+ position: relative;
+ display: inline-flex;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ height: 2rem;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ line-height: 2;
+ --tab-padding: 1rem;
+ --tw-text-opacity: 0.5;
+ --tab-color: hsl(var(--bc) / var(--tw-text-opacity, 1));
+ --tab-bg: hsl(var(--b1) / var(--tw-bg-opacity, 1));
+ --tab-border-color: hsl(var(--b3) / var(--tw-bg-opacity, 1));
+ color: var(--tab-color);
+ padding-left: var(--tab-padding, 1rem);
+ padding-right: var(--tab-padding, 1rem);
+}
+
.toast {
position: fixed;
display: flex;
@@ -884,6 +1163,12 @@ html {
border-color: hsl(var(--b1) / var(--tw-border-opacity));
}
+.btm-nav > *:where(.active) {
+ border-top-width: 2px;
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b1) / var(--tw-bg-opacity));
+}
+
.btm-nav > *.disabled,
.btm-nav > *[disabled] {
pointer-events: none;
@@ -894,12 +1179,24 @@ html {
--tw-text-opacity: 0.2;
}
+.btm-nav > * .label {
+ font-size: 1rem;
+ line-height: 1.5rem;
+}
+
.btn:active:hover,
.btn:active:focus {
animation: button-pop 0s ease-out;
transform: scale(var(--btn-focus-scale, 0.97));
}
+.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--b3) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b3) / var(--tw-bg-opacity));
+}
+
.btn:focus-visible {
outline-style: solid;
outline-width: 2px;
@@ -923,6 +1220,55 @@ html {
background-color: hsl(var(--pf) / var(--tw-bg-opacity));
}
+.btn-secondary.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--sf) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--sf) / var(--tw-bg-opacity));
+}
+
+.btn-accent.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--af) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--af) / var(--tw-bg-opacity));
+}
+
+.btn-neutral.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--nf) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--nf) / var(--tw-bg-opacity));
+}
+
+.btn-info.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--in) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--in) / var(--tw-bg-opacity));
+}
+
+.btn-success.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--su) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--su) / var(--tw-bg-opacity));
+}
+
+.btn-warning.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--wa) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--wa) / var(--tw-bg-opacity));
+}
+
+.btn-error.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--er) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--er) / var(--tw-bg-opacity));
+}
+
.btn.glass {
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
@@ -952,6 +1298,21 @@ html {
--tw-bg-opacity: 0.2;
}
+.btn-link.btn-active {
+ border-color: transparent;
+ background-color: transparent;
+ text-decoration-line: underline;
+}
+
+.btn-outline.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--bc) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--bc) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--b1) / var(--tw-text-opacity));
+}
+
.btn-outline.btn-primary {
--tw-text-opacity: 1;
color: hsl(var(--p) / var(--tw-text-opacity));
@@ -966,6 +1327,60 @@ html {
color: hsl(var(--pc) / var(--tw-text-opacity));
}
+.btn-outline.btn-secondary.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--sf) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--sf) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--sc) / var(--tw-text-opacity));
+}
+
+.btn-outline.btn-accent.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--af) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--af) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--ac) / var(--tw-text-opacity));
+}
+
+.btn-outline.btn-success.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--su) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--su) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--suc) / var(--tw-text-opacity));
+}
+
+.btn-outline.btn-info.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--in) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--in) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--inc) / var(--tw-text-opacity));
+}
+
+.btn-outline.btn-warning.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--wa) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--wa) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--wac) / var(--tw-text-opacity));
+}
+
+.btn-outline.btn-error.btn-active {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--er) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--er) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--erc) / var(--tw-text-opacity));
+}
+
.btn.btn-disabled,
.btn[disabled],
.btn:disabled {
@@ -1020,6 +1435,57 @@ html {
}
}
+.checkbox:focus-visible {
+ outline-style: solid;
+ outline-width: 2px;
+ outline-offset: 2px;
+ outline-color: hsl(var(--bc) / 1);
+}
+
+.checkbox:checked,
+ .checkbox[checked="true"],
+ .checkbox[aria-checked="true"] {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--bc) / var(--tw-bg-opacity));
+ background-repeat: no-repeat;
+ animation: checkmark var(--animation-input, 0.2s) ease-out;
+ background-image: linear-gradient(-45deg, transparent 65%, hsl(var(--chkbg)) 65.99%),
+ linear-gradient(45deg, transparent 75%, hsl(var(--chkbg)) 75.99%),
+ linear-gradient(-45deg, hsl(var(--chkbg)) 40%, transparent 40.99%),
+ linear-gradient(
+ 45deg,
+ hsl(var(--chkbg)) 30%,
+ hsl(var(--chkfg)) 30.99%,
+ hsl(var(--chkfg)) 40%,
+ transparent 40.99%
+ ),
+ linear-gradient(-45deg, hsl(var(--chkfg)) 50%, hsl(var(--chkbg)) 50.99%);
+}
+
+.checkbox:indeterminate {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--bc) / var(--tw-bg-opacity));
+ background-repeat: no-repeat;
+ animation: checkmark var(--animation-input, 0.2s) ease-out;
+ background-image: linear-gradient(90deg, transparent 80%, hsl(var(--chkbg)) 80%),
+ linear-gradient(-90deg, transparent 80%, hsl(var(--chkbg)) 80%),
+ linear-gradient(
+ 0deg,
+ hsl(var(--chkbg)) 43%,
+ hsl(var(--chkfg)) 43%,
+ hsl(var(--chkfg)) 57%,
+ hsl(var(--chkbg)) 57%
+ );
+}
+
+.checkbox:disabled {
+ cursor: not-allowed;
+ border-color: transparent;
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--bc) / var(--tw-bg-opacity));
+ opacity: 0.2;
+}
+
@keyframes checkmark {
0% {
background-position-y: 5px;
@@ -1034,6 +1500,80 @@ html {
}
}
+[dir="rtl"] .checkbox:checked,
+ [dir="rtl"] .checkbox[checked="true"],
+ [dir="rtl"] .checkbox[aria-checked="true"] {
+ background-image: linear-gradient(45deg, transparent 65%, hsl(var(--chkbg)) 65.99%),
+ linear-gradient(-45deg, transparent 75%, hsl(var(--chkbg)) 75.99%),
+ linear-gradient(45deg, hsl(var(--chkbg)) 40%, transparent 40.99%),
+ linear-gradient(
+ -45deg,
+ hsl(var(--chkbg)) 30%,
+ hsl(var(--chkfg)) 30.99%,
+ hsl(var(--chkfg)) 40%,
+ transparent 40.99%
+ ),
+ linear-gradient(45deg, hsl(var(--chkfg)) 50%, hsl(var(--chkbg)) 50.99%);
+}
+
+.divider:before {
+ background-color: hsl(var(--bc) / var(--tw-bg-opacity));
+ --tw-bg-opacity: 0.1;
+}
+
+.divider:after {
+ background-color: hsl(var(--bc) / var(--tw-bg-opacity));
+ --tw-bg-opacity: 0.1;
+}
+
+.divider:not(:empty) {
+ gap: 1rem;
+}
+
+.drawer-toggle:checked ~ .drawer-side > .drawer-overlay {
+ background-color: hsl(0 0% 0%/0.4);
+}
+
+.drawer-toggle:focus-visible ~ .drawer-content label.drawer-button {
+ outline-style: solid;
+ outline-width: 2px;
+ outline-offset: 2px;
+}
+
+.input[list]::-webkit-calendar-picker-indicator {
+ line-height: 1em;
+}
+
+.input:focus {
+ outline-style: solid;
+ outline-width: 2px;
+ outline-offset: 2px;
+ outline-color: hsl(var(--bc) / 0.2);
+}
+
+.input-disabled,
+ .input:disabled,
+ .input[disabled] {
+ cursor: not-allowed;
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--b2) / var(--tw-border-opacity));
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b2) / var(--tw-bg-opacity));
+ --tw-text-opacity: 0.2;
+}
+
+.input-disabled::-moz-placeholder, .input:disabled::-moz-placeholder, .input[disabled]::-moz-placeholder {
+ color: hsl(var(--bc) / var(--tw-placeholder-opacity));
+ --tw-placeholder-opacity: 0.2;
+}
+
+.input-disabled::placeholder,
+ .input:disabled::placeholder,
+ .input[disabled]::placeholder {
+ color: hsl(var(--bc) / var(--tw-placeholder-opacity));
+ --tw-placeholder-opacity: 0.2;
+}
+
.link:focus {
outline: 2px solid transparent;
outline-offset: 2px;
@@ -1049,6 +1589,134 @@ html {
mask-image: url("data:image/svg+xml,%3csvg width='200' height='200' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M100 0C20 0 0 20 0 100s20 100 100 100 100-20 100-100S180 0 100 0Z'/%3e%3c/svg%3e");
}
+:where(.menu li:empty) {
+ background-color: hsl(var(--bc) / 0.1);
+ margin: 0.5rem 1rem;
+ height: 1px;
+}
+
+.menu :where(li ul):before {
+ position: absolute;
+ left: 0px;
+ top: 0.75rem;
+ bottom: 0.75rem;
+ width: 1px;
+ background-color: hsl(var(--bc) / 0.1);
+ content: "";
+}
+
+.menu :where(li:not(.menu-title) > *:not(ul):not(details):not(.menu-title)),
+.menu :where(li:not(.menu-title) > details > summary:not(.menu-title)) {
+ padding-left: 1rem;
+ padding-right: 1rem;
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+ text-align: left;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
+ transition-duration: 200ms;
+ border-radius: var(--rounded-btn, 0.5rem);
+ text-wrap: balance;
+}
+
+:where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):not(summary):not(.active).focus,
+ :where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):not(summary):not(.active):focus,
+ :where(.menu li:not(.menu-title):not(.disabled) > *:not(ul):not(details):not(.menu-title)):is(summary):not(.active):focus-visible,
+ :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):not(summary):not(.active).focus,
+ :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):not(summary):not(.active):focus,
+ :where(.menu li:not(.menu-title):not(.disabled) > details > summary:not(.menu-title)):is(summary):not(.active):focus-visible {
+ cursor: pointer;
+ background-color: hsl(var(--bc) / 0.1);
+ --tw-text-opacity: 1;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+}
+
+.menu li > *:not(ul):not(.menu-title):not(details):active,
+.menu li > *:not(ul):not(.menu-title):not(details).active,
+.menu li > details > summary:active {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--n) / var(--tw-bg-opacity));
+ --tw-text-opacity: 1;
+ color: hsl(var(--nc) / var(--tw-text-opacity));
+}
+
+.menu :where(li > details > summary)::-webkit-details-marker {
+ display: none;
+}
+
+.menu :where(li > details > summary):after,
+.menu :where(li > .menu-dropdown-toggle):after {
+ justify-self: end;
+ display: block;
+ margin-top: -0.5rem;
+ height: 0.5rem;
+ width: 0.5rem;
+ transform: rotate(45deg);
+ transition-property: transform, margin-top;
+ transition-duration: 0.3s;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ content: "";
+ transform-origin: 75% 75%;
+ box-shadow: 2px 2px;
+ pointer-events: none;
+}
+
+.menu :where(li > details[open] > summary):after,
+.menu :where(li > .menu-dropdown-toggle.menu-dropdown-show):after {
+ transform: rotate(225deg);
+ margin-top: 0;
+}
+
+.mockup-browser .mockup-browser-toolbar .input {
+ position: relative;
+ margin-left: auto;
+ margin-right: auto;
+ display: block;
+ height: 1.75rem;
+ width: 24rem;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b2) / var(--tw-bg-opacity));
+ padding-left: 2rem;
+}
+
+.mockup-browser .mockup-browser-toolbar .input:before {
+ content: "";
+ position: absolute;
+ top: 50%;
+ left: 0.5rem;
+ aspect-ratio: 1 / 1;
+ height: 0.75rem;
+ --tw-translate-y: -50%;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+ border-radius: 9999px;
+ border-width: 2px;
+ border-color: currentColor;
+ opacity: 0.6;
+}
+
+.mockup-browser .mockup-browser-toolbar .input:after {
+ content: "";
+ position: absolute;
+ top: 50%;
+ left: 1.25rem;
+ height: 0.5rem;
+ --tw-translate-y: 25%;
+ --tw-rotate: -45deg;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+ border-radius: 9999px;
+ border-width: 1px;
+ border-color: currentColor;
+ opacity: 0.6;
+}
+
@keyframes modal-pop {
0% {
opacity: 0;
@@ -1089,6 +1757,52 @@ html {
}
}
+.tab.tab-active:not(.tab-disabled):not([disabled]) {
+ border-color: hsl(var(--bc) / var(--tw-border-opacity));
+ --tw-border-opacity: 1;
+ --tw-text-opacity: 1;
+}
+
+.tab:focus {
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+}
+
+.tab:focus-visible {
+ outline: 2px solid currentColor;
+ outline-offset: -3px;
+}
+
+.tab:focus-visible.tab-lifted {
+ border-bottom-right-radius: var(--tab-radius, 0.5rem);
+ border-bottom-left-radius: var(--tab-radius, 0.5rem);
+}
+
+.tab-disabled,
+ .tab[disabled] {
+ cursor: not-allowed;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+ --tw-text-opacity: 0.2;
+}
+
+.tabs-boxed .tab {
+ border-radius: var(--rounded-btn, 0.5rem);
+}
+
+.table tr.active,
+ .table tr.active:nth-child(even),
+ .table-zebra tbody tr:nth-child(even) {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b2) / var(--tw-bg-opacity));
+}
+
+.table-zebra tr.active,
+ .table-zebra tr.active:nth-child(even),
+ .table-zebra-zebra tbody tr:nth-child(even) {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b3) / var(--tw-bg-opacity));
+}
+
.toast > * {
animation: toast-pop 0.25s ease-out;
}
@@ -1105,6 +1819,65 @@ html {
}
}
+.glass,
+ .glass.btn-active {
+ border: none;
+ -webkit-backdrop-filter: blur(var(--glass-blur, 40px));
+ backdrop-filter: blur(var(--glass-blur, 40px));
+ background-color: transparent;
+ background-image: linear-gradient(
+ 135deg,
+ rgb(255 255 255 / var(--glass-opacity, 30%)) 0%,
+ rgb(0 0 0 / 0%) 100%
+ ),
+ linear-gradient(
+ var(--glass-reflex-degree, 100deg),
+ rgb(255 255 255 / var(--glass-reflex-opacity, 10%)) 25%,
+ rgb(0 0 0 / 0%) 25%
+ );
+ box-shadow: 0 0 0 1px rgb(255 255 255 / var(--glass-border-opacity, 10%)) inset,
+ 0 0 0 2px rgb(0 0 0 / 5%);
+ text-shadow: 0 1px rgb(0 0 0 / var(--glass-text-shadow-opacity, 5%));
+}
+
+@media (hover: hover) {
+ .glass.btn-active {
+ border: none;
+ -webkit-backdrop-filter: blur(var(--glass-blur, 40px));
+ backdrop-filter: blur(var(--glass-blur, 40px));
+ background-color: transparent;
+ background-image: linear-gradient(
+ 135deg,
+ rgb(255 255 255 / var(--glass-opacity, 30%)) 0%,
+ rgb(0 0 0 / 0%) 100%
+ ),
+ linear-gradient(
+ var(--glass-reflex-degree, 100deg),
+ rgb(255 255 255 / var(--glass-reflex-opacity, 10%)) 25%,
+ rgb(0 0 0 / 0%) 25%
+ );
+ box-shadow: 0 0 0 1px rgb(255 255 255 / var(--glass-border-opacity, 10%)) inset,
+ 0 0 0 2px rgb(0 0 0 / 5%);
+ text-shadow: 0 1px rgb(0 0 0 / var(--glass-text-shadow-opacity, 5%));
+ }
+}
+
+.btm-nav-xs > *:where(.active) {
+ border-top-width: 1px;
+}
+
+.btm-nav-sm > *:where(.active) {
+ border-top-width: 2px;
+}
+
+.btm-nav-md > *:where(.active) {
+ border-top-width: 2px;
+}
+
+.btm-nav-lg > *:where(.active) {
+ border-top-width: 4px;
+}
+
.btn-sm {
height: 2rem;
padding-left: 0.75rem;
@@ -1165,6 +1938,32 @@ html {
padding: 0px;
}
+.drawer-open > .drawer-toggle {
+ display: none;
+}
+
+.drawer-open > .drawer-toggle ~ .drawer-side {
+ pointer-events: auto;
+ visibility: visible;
+ position: sticky;
+ display: block;
+ width: auto;
+ overscroll-behavior: auto;
+}
+
+.drawer-open > .drawer-toggle ~ .drawer-side > *:not(.drawer-overlay) {
+ transform: translateX(0%);
+}
+
+[dir="rtl"] .drawer-open > .drawer-toggle ~ .drawer-side > *:not(.drawer-overlay) {
+ transform: translateX(0%);
+}
+
+.drawer-open > .drawer-toggle:checked ~ .drawer-side {
+ pointer-events: auto;
+ visibility: visible;
+}
+
:where(.toast) {
right: 0px;
left: auto;
@@ -1313,6 +2112,11 @@ html {
border-bottom-right-radius: var(--rounded-btn, 0.5rem);
}
+.drawer-open > .drawer-toggle ~ .drawer-side > .drawer-overlay {
+ cursor: default;
+ background-color: transparent;
+}
+
.static {
position: static;
}
@@ -1380,6 +2184,10 @@ html {
height: 1.5rem;
}
+.h-full {
+ height: 100%;
+}
+
.w-full {
width: 100%;
}
@@ -1413,6 +2221,10 @@ html {
width: 1.5rem;
}
+.w-80 {
+ width: 20rem;
+}
+
.max-w-lg {
max-width: 32rem;
}
@@ -1443,10 +2255,18 @@ html {
flex-direction: row;
}
+.flex-col {
+ flex-direction: column;
+}
+
.content-start {
align-content: flex-start;
}
+.items-center {
+ align-items: center;
+}
+
.justify-start {
justify-content: flex-start;
}
@@ -1455,6 +2275,12 @@ html {
justify-content: center;
}
+.space-y-2 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
+}
+
.rounded-full {
border-radius: 9999px;
}
@@ -1507,6 +2333,21 @@ html {
background-color: rgb(209 213 219 / var(--tw-bg-opacity));
}
+.bg-base-200 {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b2) / var(--tw-bg-opacity));
+}
+
+.bg-base-100 {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--b1) / var(--tw-bg-opacity));
+}
+
+.bg-primary {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--p) / var(--tw-bg-opacity));
+}
+
.bg-opacity-10 {
--tw-bg-opacity: 0.1;
}
@@ -1523,6 +2364,10 @@ html {
padding: 1.25rem;
}
+.p-4 {
+ padding: 1rem;
+}
+
.py-5 {
padding-top: 1.25rem;
padding-bottom: 1.25rem;
@@ -1537,10 +2382,20 @@ html {
line-height: 1.75rem;
}
+.text-lg {
+ font-size: 1.125rem;
+ line-height: 1.75rem;
+}
+
.normal-case {
text-transform: none;
}
+.text-base-content {
+ --tw-text-opacity: 1;
+ color: hsl(var(--bc) / var(--tw-text-opacity));
+}
+
.opacity-0 {
opacity: 0;
}
@@ -1549,6 +2404,45 @@ html {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
+@media (min-width: 1024px) {
+ .lg\:drawer-open > .drawer-toggle {
+ display: none;
+ }
+
+ .lg\:drawer-open > .drawer-toggle ~ .drawer-side {
+ pointer-events: auto;
+ visibility: visible;
+ position: sticky;
+ display: block;
+ width: auto;
+ overscroll-behavior: auto;
+ }
+
+ .lg\:drawer-open > .drawer-toggle ~ .drawer-side > *:not(.drawer-overlay) {
+ transform: translateX(0%);
+ }
+
+ [dir="rtl"] .lg\:drawer-open > .drawer-toggle ~ .drawer-side > *:not(.drawer-overlay) {
+ transform: translateX(0%);
+ }
+
+ .lg\:drawer-open > .drawer-toggle:checked ~ .drawer-side {
+ pointer-events: auto;
+ visibility: visible;
+ }
+
+ .lg\:drawer-open > .drawer-toggle ~ .drawer-side > .drawer-overlay {
+ cursor: default;
+ background-color: transparent;
+ }
+}
+
.hover\:bg-transparent:hover {
background-color: transparent;
}
+
+@media (min-width: 1024px) {
+ .lg\:hidden {
+ display: none;
+ }
+}
From 76f5f42ee5a48f2ec5116fd249f56b2196159051 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Mon, 7 Aug 2023 18:42:41 -0400
Subject: [PATCH 036/119] random fixes
---
Cargo.lock | 174 +++++++++++++++---
Cargo.toml | 6 +
.../src/site/components/toasted_susp.rs | 4 +-
.../src/site/routes/servers/id/overview.rs | 4 +-
.../src/site/routes/servers/id/sidebar.rs | 4 +-
5 files changed, 159 insertions(+), 33 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index aba6481e..6a11c3ff 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -452,6 +452,18 @@ version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
+[[package]]
+name = "bitvec"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
[[package]]
name = "block-buffer"
version = "0.10.4"
@@ -488,6 +500,29 @@ version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
+[[package]]
+name = "bytecheck"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627"
+dependencies = [
+ "bytecheck_derive",
+ "ptr_meta",
+ "simdutf8",
+ "uuid",
+]
+
+[[package]]
+name = "bytecheck_derive"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "bytecount"
version = "0.6.3"
@@ -1370,6 +1405,12 @@ dependencies = [
"percent-encoding",
]
+[[package]]
+name = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
[[package]]
name = "futures"
version = "0.3.28"
@@ -2049,8 +2090,7 @@ dependencies = [
[[package]]
name = "leptos"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d08fd7674758f996050217a8aff9e584d033c2e5c882cd3f52fb5090dc361dd"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"cfg-if",
"leptos_config",
@@ -2066,8 +2106,7 @@ dependencies = [
[[package]]
name = "leptos_actix"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c122547e0a04d6b2efaef999b3165f03eb1b1284fdb298f05bde9107ed16ec2"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"actix-http",
"actix-web",
@@ -2085,8 +2124,7 @@ dependencies = [
[[package]]
name = "leptos_config"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e5c13a1ae92b5a545cc013205288751fb2fef521de5a092067fd8429ad343e8"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"config",
"regex",
@@ -2098,8 +2136,7 @@ dependencies = [
[[package]]
name = "leptos_dom"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35994afab1dca68a46c7b40a29d40d84a2e06e1b1fa0d5c5915ade4f4f2611ee"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"async-recursion",
"cfg-if",
@@ -2128,8 +2165,7 @@ dependencies = [
[[package]]
name = "leptos_hot_reload"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a088a4dd5489941a9cc73719148f217c78f0d761a50e025739653c3b7f9d484"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"anyhow",
"camino",
@@ -2157,8 +2193,7 @@ dependencies = [
[[package]]
name = "leptos_integration_utils"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfd4a097f1870172f5079e44af99fb5d5f02cd856db6b32a6ac98cc58f1a1f47"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"futures",
"leptos",
@@ -2171,8 +2206,7 @@ dependencies = [
[[package]]
name = "leptos_macro"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bdd7a21d20ca21bb12d67d050d4b0ad9973b156bce98f499f8b1789f11959dd"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"attribute-derive",
"cfg-if",
@@ -2194,8 +2228,7 @@ dependencies = [
[[package]]
name = "leptos_meta"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed4e4855b6d0047f1cdbf0e9d41b76a1b596ec374f844d2bae1e48f2d2df70d8"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"cfg-if",
"indexmap 2.0.0",
@@ -2208,14 +2241,14 @@ dependencies = [
[[package]]
name = "leptos_reactive"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5500318e457b4ab841722a5988e8db0def1ee7ac66b816ba9073c100c4984a"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"base64 0.21.2",
"cfg-if",
"futures",
"indexmap 2.0.0",
"js-sys",
+ "rkyv",
"rustc-hash",
"self_cell",
"serde",
@@ -2233,8 +2266,7 @@ dependencies = [
[[package]]
name = "leptos_router"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57a6cd29a56992923c9bad3c814ab9d7a78bf0bfec80c8f4dfbf049144fa5828"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"cached",
"cfg-if",
@@ -2263,8 +2295,7 @@ dependencies = [
[[package]]
name = "leptos_server"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28d958deee3c7ffda892a67ac4a47500aebbaf00b11d217cfe6fd494c297818"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"inventory",
"lazy_static",
@@ -3089,6 +3120,26 @@ dependencies = [
"unescape",
]
+[[package]]
+name = "ptr_meta"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1"
+dependencies = [
+ "ptr_meta_derive",
+]
+
+[[package]]
+name = "ptr_meta_derive"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "pulldown-cmark"
version = "0.9.3"
@@ -3137,6 +3188,12 @@ dependencies = [
"syn 2.0.28",
]
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
[[package]]
name = "rand"
version = "0.8.5"
@@ -3234,6 +3291,15 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
+[[package]]
+name = "rend"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab"
+dependencies = [
+ "bytecheck",
+]
+
[[package]]
name = "reqwest"
version = "0.11.18"
@@ -3301,6 +3367,34 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "rkyv"
+version = "0.7.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58"
+dependencies = [
+ "bitvec",
+ "bytecheck",
+ "hashbrown 0.12.3",
+ "ptr_meta",
+ "rend",
+ "rkyv_derive",
+ "seahash",
+ "tinyvec",
+ "uuid",
+]
+
+[[package]]
+name = "rkyv_derive"
+version = "0.7.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "ron"
version = "0.7.1"
@@ -3515,6 +3609,12 @@ dependencies = [
"untrusted",
]
+[[package]]
+name = "seahash"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
+
[[package]]
name = "sec1"
version = "0.7.3"
@@ -3811,8 +3911,7 @@ dependencies = [
[[package]]
name = "server_fn"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "644216cf54c944da2d7fc7a75337a35dc39de19130be3fd88fd58674719a1b5b"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"ciborium",
"const_format",
@@ -3836,8 +3935,7 @@ dependencies = [
[[package]]
name = "server_fn_macro"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1db2cd1a054f5c6ec168982241f6cdad083591d6c68449e666c839ec421bfc54"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"const_format",
"proc-macro-error",
@@ -3851,8 +3949,7 @@ dependencies = [
[[package]]
name = "server_fn_macro_default"
version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35ee7b18c66e7a30b1855096cee24d540925825ce91193f42fae322033b109c1"
+source = "git+https://github.com/leptos-rs/leptos.git#f01b982cff3dc7d6fdca1208fe5668faf4ae7251"
dependencies = [
"server_fn_macro",
"syn 2.0.28",
@@ -3909,6 +4006,12 @@ dependencies = [
"rand_core",
]
+[[package]]
+name = "simdutf8"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
+
[[package]]
name = "siphasher"
version = "0.3.10"
@@ -4221,6 +4324,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
[[package]]
name = "tempfile"
version = "3.7.0"
@@ -5090,6 +5199,15 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "wyz"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+dependencies = [
+ "tap",
+]
+
[[package]]
name = "xxhash-rust"
version = "0.8.6"
diff --git a/Cargo.toml b/Cargo.toml
index 4ce04e12..eed97b89 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,3 +16,9 @@ opt-level = 'z'
lto = true
codegen-units = 1
panic = "abort"
+
+[patch.crates-io]
+leptos = { git = "https://github.com/leptos-rs/leptos.git"}
+leptos_meta = {git = "https://github.com/leptos-rs/leptos.git"}
+leptos_actix = {git = "https://github.com/leptos-rs/leptos.git"}
+leptos_router = {git = "https://github.com/leptos-rs/leptos.git"}
diff --git a/crates/website/src/site/components/toasted_susp.rs b/crates/website/src/site/components/toasted_susp.rs
index 93fe83a8..69c8f250 100644
--- a/crates/website/src/site/components/toasted_susp.rs
+++ b/crates/website/src/site/components/toasted_susp.rs
@@ -143,7 +143,9 @@ where
toast(cx, Toast::error(err.to_string()));
}
fallback.with_value(|f| f())
- }>{children.with_value(|c| c(cx))}
+ }>
+ {children.with_value(|c| c(cx))}
+
}
}
diff --git a/crates/website/src/site/routes/servers/id/overview.rs b/crates/website/src/site/routes/servers/id/overview.rs
index b0d3e1d0..5ae87c43 100644
--- a/crates/website/src/site/routes/servers/id/overview.rs
+++ b/crates/website/src/site/routes/servers/id/overview.rs
@@ -6,12 +6,12 @@ use crate::site::components::ToastedSusp;
pub fn Overview(cx: Scope) -> impl IntoView {
let guild = expect_context::(cx);
- let content = move || {
+ let content = move |cx| {
guild.with(cx, |g| {
g.as_ref()
.map(|g| format!("{g:?}"))
.map_err(|e| e.to_owned())
})
};
- view! { cx, {content} }
+ view! { cx, {move || content(cx)} }
}
diff --git a/crates/website/src/site/routes/servers/id/sidebar.rs b/crates/website/src/site/routes/servers/id/sidebar.rs
index 09ff9800..bae66d25 100644
--- a/crates/website/src/site/routes/servers/id/sidebar.rs
+++ b/crates/website/src/site/routes/servers/id/sidebar.rs
@@ -17,7 +17,7 @@ pub enum Tab {
pub fn SideBar(cx: Scope, active: Memo) -> impl IntoView {
let guild = expect_context::(cx);
- let title = move || {
+ let title = move |cx| {
guild.with(cx, |g| {
g.as_ref()
.ok()
@@ -44,7 +44,7 @@ pub fn SideBar(cx: Scope, active: Memo) -> impl IntoView {
- {title}
+ {move || title(cx)}
From 55c328cd32fe3405bc5827b9038bd2fd5c8e8219 Mon Sep 17 00:00:00 2001
From: CircuitSacul
Date: Mon, 7 Aug 2023 22:20:57 -0400
Subject: [PATCH 037/119] misc styling
---
crates/website/src/site/routes/mod.rs | 27 +++++++------------
.../src/site/routes/servers/id/sidebar.rs | 14 ++++++----
crates/website/style/output.css | 4 +++
3 files changed, 23 insertions(+), 22 deletions(-)
diff --git a/crates/website/src/site/routes/mod.rs b/crates/website/src/site/routes/mod.rs
index 2762acbe..c52b9a23 100644
--- a/crates/website/src/site/routes/mod.rs
+++ b/crates/website/src/site/routes/mod.rs
@@ -30,10 +30,14 @@ pub fn Index(cx: Scope) -> impl IntoView {
-
+
+
+
-
-
+
+
+
+
@@ -47,27 +51,16 @@ fn RedirectToServers(cx: Scope) -> impl IntoView {
view! { cx, "Redirecting..." }
}
-#[component(transparent)]
-fn WebsiteRoutes(cx: Scope) -> impl IntoView {
- view! { cx,
-
-
-
-
-
-
-
-
- }
-}
-
#[component(transparent)]
fn DashboardRoutes(cx: Scope) -> impl IntoView {
view! { cx,
+
+
+
diff --git a/crates/website/src/site/routes/servers/id/sidebar.rs b/crates/website/src/site/routes/servers/id/sidebar.rs
index bae66d25..c10cffe1 100644
--- a/crates/website/src/site/routes/servers/id/sidebar.rs
+++ b/crates/website/src/site/routes/servers/id/sidebar.rs
@@ -19,10 +19,14 @@ pub fn SideBar(cx: Scope, active: Memo) -> impl IntoView {
let title = move |cx| {
guild.with(cx, |g| {
- g.as_ref()
- .ok()
- .and_then(|g| g.as_ref())
- .map(|g| g.http.name.to_owned())
+ g.as_ref().ok().and_then(|g| g.as_ref()).map(|g| {
+ let name = &g.http.name;
+ if name.len() > 23 {
+ format!("{}...", &name[0..20])
+ } else {
+ name.to_owned()
+ }
+ })
})
};
@@ -40,7 +44,7 @@ pub fn SideBar(cx: Scope, active: Memo) -> impl IntoView {
-