├── .devcontainer ├── .bash_aliases ├── Dockerfile ├── devcontainer.json ├── docker-compose.yml └── ps1.bash ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── accordian.rs ├── alert.rs ├── app_layout.rs ├── avatar.rs ├── blank_slate.rs ├── button.rs ├── card.rs ├── check_box.rs ├── drawer.rs ├── drop_down.rs ├── input.rs ├── label.rs ├── lib.rs ├── marketing ├── benefits.rs ├── customer_logos.rs ├── extra_footer.rs ├── faq_accordian.rs ├── features.rs ├── hero.rs ├── image_feature.rs ├── mod.rs ├── problem_solution.rs ├── quad_feature.rs ├── security.rs ├── small_image_feature.rs ├── team.rs ├── testamonials.rs ├── video_hero.rs └── webinar.rs ├── modal.rs ├── nav_item.rs ├── pagination.rs ├── range.rs ├── relative_time.rs ├── select.rs ├── tab_container.rs ├── text_area.rs ├── time_line.rs └── tooltip.rs /.devcontainer/.bash_aliases: -------------------------------------------------------------------------------- 1 | # Git aliases. 2 | alias gst='git status' 3 | alias gcm='git checkout main' 4 | alias c=clear 5 | alias gp='git push' 6 | alias gcam='git commit -a -m' 7 | alias gpsup="git push --set-upstream origin $(git symbolic-ref -q HEAD | sed -e 's|^refs/heads/||')" 8 | alias gcb='git checkout -b' 9 | alias gcr='f() { git checkout -b $1 origin/$1; }; f' 10 | alias gitsetup='git config --global user.name \$NAME && git config --global user.email \$EMAIL' 11 | 12 | # Cargo watch 13 | alias cw='mold -run cargo watch --no-gitignore -i "*.scss" -i "*.ts" -i node_modules -x run' 14 | 15 | # npm 16 | alias nrs='npm run start' 17 | 18 | # Database 19 | alias dbmate='dbmate --no-dump-schema --migrations-dir /workspace/crates/db/migrations' 20 | alias db='psql $DATABASE_URL' 21 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM purtontech/rust-on-nails-devcontainer:1.3.13 AS development 2 | 3 | COPY ps1.bash . 4 | RUN cat ps1.bash >> ~/.bashrc && sudo rm ps1.bash 5 | 6 | COPY .bash_aliases /home/vscode/.bash_aliases 7 | 8 | # Enable our git hooks and set the permisisons on docker sock. 9 | RUN echo 'git config core.hooksPath /workspace/.devcontainer/.githooks' >> ~/.bashrc 10 | 11 | # all the volumes configured in the docker-compose.yml 12 | ARG USERNAME=vscode 13 | RUN sudo mkdir -p /workspace/target && sudo chown $USERNAME:$USERNAME /workspace/target 14 | #RUN sudo mkdir -p /workspace/crates/asset-pipeline/node_modules && sudo chown $USERNAME:$USERNAME /workspace/crates/asset-pipeline/node_modules 15 | 16 | # Install cargo-leptos 17 | RUN cargo binstall cargo-release --no-confirm -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.224.3/containers/rust-postgres 3 | { 4 | "name": "daisy-rsx", 5 | "dockerComposeFile": [ 6 | "docker-compose.yml" 7 | ], 8 | "service": "development", 9 | "workspaceFolder": "/workspace", 10 | "mounts": [ 11 | "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached" 12 | ], 13 | // Set *default* container specific settings.json values on container create. 14 | "customizations": { 15 | "vscode": { 16 | "settings": { 17 | "lldb.executable": "/usr/bin/lldb", 18 | // VS Code don't watch files under ./target 19 | "files.watcherExclude": { 20 | "**/target/**": true 21 | }, 22 | "rust-analyzer.checkOnSave.command": "clippy" 23 | }, 24 | // Add the IDs of extensions you want installed when the container is created. 25 | "extensions": [ 26 | "vadimcn.vscode-lldb", 27 | "mutantdino.resourcemonitor", 28 | "rust-lang.rust-analyzer", 29 | "tamasfe.even-better-toml", 30 | "serayuzgur.crates" 31 | ] 32 | } 33 | }, 34 | 35 | "remoteEnv": { 36 | // You can create env vars on your local machine and they will get passed into your container. 37 | "EMAIL": "${localEnv:EMAIL}", 38 | "NAME": "${localEnv:NAME}", 39 | // Pass in the host directory for Docker mount commands from inside the container 40 | "HOST_PROJECT_PATH": "${localWorkspaceFolder}" 41 | }, 42 | 43 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 44 | // "forwardPorts": [5432], 45 | 46 | // Use 'postCreateCommand' to run commands after the container is created. 47 | // "postCreateCommand": "rustc --version", 48 | 49 | // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 50 | "remoteUser": "vscode" 51 | } 52 | -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | services: 3 | 4 | development: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | 9 | volumes: 10 | - ..:/workspace:cached 11 | # Give access to ssh keys on the host (Is there a better way to do this?) 12 | - ~/.ssh:/home/host-ssh:cached 13 | # We need this so docker in docker works 14 | - /var/run/docker.sock:/var/run/docker.sock 15 | - target:/workspace/target # Set target as a volume for performance. 16 | # Uncomment the next line to improve performance when using node. 17 | #- node_modules:/workspace/crates/asset-pipeline/node_modules 18 | 19 | environment: 20 | DATABASE_URL: postgresql://postgres:testpassword@db:5432/postgres?sslmode=disable 21 | 22 | # Overrides default command so things don't shut down after the process ends. 23 | command: sleep infinity 24 | 25 | working_dir: /workspace 26 | 27 | volumes: 28 | target: 29 | node_modules: 30 | -------------------------------------------------------------------------------- /.devcontainer/ps1.bash: -------------------------------------------------------------------------------- 1 | parse_git_branch() { 2 | branch=$(git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/') 3 | if [ ! -z "$branch" ]; then 4 | echo "$branch" 5 | fi 6 | } 7 | export PS1="\[\033[32m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\] \n$ " 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "askama_escape" 7 | version = "0.10.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" 10 | 11 | [[package]] 12 | name = "autocfg" 13 | version = "1.3.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 16 | 17 | [[package]] 18 | name = "bitflags" 19 | version = "2.5.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 22 | 23 | [[package]] 24 | name = "cfg-if" 25 | version = "1.0.0" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 28 | 29 | [[package]] 30 | name = "const_format" 31 | version = "0.2.34" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" 34 | dependencies = [ 35 | "const_format_proc_macros", 36 | ] 37 | 38 | [[package]] 39 | name = "const_format_proc_macros" 40 | version = "0.2.34" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" 43 | dependencies = [ 44 | "proc-macro2", 45 | "quote", 46 | "unicode-xid", 47 | ] 48 | 49 | [[package]] 50 | name = "convert_case" 51 | version = "0.6.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" 54 | dependencies = [ 55 | "unicode-segmentation", 56 | ] 57 | 58 | [[package]] 59 | name = "daisy_rsx" 60 | version = "0.1.14" 61 | dependencies = [ 62 | "dioxus", 63 | "dioxus-ssr", 64 | ] 65 | 66 | [[package]] 67 | name = "darling" 68 | version = "0.20.9" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" 71 | dependencies = [ 72 | "darling_core", 73 | "darling_macro", 74 | ] 75 | 76 | [[package]] 77 | name = "darling_core" 78 | version = "0.20.9" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" 81 | dependencies = [ 82 | "fnv", 83 | "ident_case", 84 | "proc-macro2", 85 | "quote", 86 | "syn", 87 | ] 88 | 89 | [[package]] 90 | name = "darling_macro" 91 | version = "0.20.9" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" 94 | dependencies = [ 95 | "darling_core", 96 | "quote", 97 | "syn", 98 | ] 99 | 100 | [[package]] 101 | name = "dioxus" 102 | version = "0.6.0" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "16c89dda102f1ff3bbe54a8d3daa4cf5cae17595f54b6338e2c42593a994303a" 105 | dependencies = [ 106 | "dioxus-core", 107 | "dioxus-core-macro", 108 | "dioxus-html", 109 | "dioxus-signals", 110 | ] 111 | 112 | [[package]] 113 | name = "dioxus-core" 114 | version = "0.6.0" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "39093c4358bc8b6c80728f9cdc7e8854cdd8ecf8b932fa2864817f6df0103ff0" 117 | dependencies = [ 118 | "const_format", 119 | "dioxus-core-types", 120 | "futures-channel", 121 | "futures-util", 122 | "generational-box", 123 | "longest-increasing-subsequence", 124 | "rustc-hash", 125 | "rustversion", 126 | "serde", 127 | "slab", 128 | "slotmap", 129 | "tracing", 130 | "warnings", 131 | ] 132 | 133 | [[package]] 134 | name = "dioxus-core-macro" 135 | version = "0.6.0" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "59cb17b8f2cea9a43b34f70412b7d77ca4c78f696546cfa717837d98c7be4117" 138 | dependencies = [ 139 | "convert_case", 140 | "dioxus-rsx", 141 | "proc-macro2", 142 | "quote", 143 | "syn", 144 | ] 145 | 146 | [[package]] 147 | name = "dioxus-core-types" 148 | version = "0.6.0" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "5a6f64e5d70de1e1492bc845c1f99e3687195a6134598437be6186b768315aa0" 151 | dependencies = [ 152 | "once_cell", 153 | ] 154 | 155 | [[package]] 156 | name = "dioxus-hooks" 157 | version = "0.6.0" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "28dc7127b10fd8e50cec15510674c7852cfa44069cc3771ccace8130a29714b2" 160 | dependencies = [ 161 | "dioxus-core", 162 | "dioxus-signals", 163 | "futures-channel", 164 | "futures-util", 165 | "generational-box", 166 | "rustversion", 167 | "slab", 168 | "tracing", 169 | "warnings", 170 | ] 171 | 172 | [[package]] 173 | name = "dioxus-html" 174 | version = "0.6.0" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "e6464a7b8da0f7c63778ddb96c2a55c5e159c58aed07c582991654ba12356eb1" 177 | dependencies = [ 178 | "dioxus-core", 179 | "dioxus-core-macro", 180 | "dioxus-core-types", 181 | "dioxus-hooks", 182 | "dioxus-html-internal-macro", 183 | "enumset", 184 | "euclid", 185 | "futures-channel", 186 | "generational-box", 187 | "keyboard-types", 188 | "lazy-js-bundle", 189 | "rustversion", 190 | "tracing", 191 | ] 192 | 193 | [[package]] 194 | name = "dioxus-html-internal-macro" 195 | version = "0.6.0" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "7d6921c8f0374c8d2fc9024db455f9e1a71ba1b723d80c60ea5d575aea3de163" 198 | dependencies = [ 199 | "convert_case", 200 | "proc-macro2", 201 | "quote", 202 | "syn", 203 | ] 204 | 205 | [[package]] 206 | name = "dioxus-rsx" 207 | version = "0.6.0" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "f37fa830dd01a3b727fa145f5c10f45e0972434ee4d64270a3abb46da3dc78c4" 210 | dependencies = [ 211 | "proc-macro2", 212 | "proc-macro2-diagnostics", 213 | "quote", 214 | "syn", 215 | ] 216 | 217 | [[package]] 218 | name = "dioxus-signals" 219 | version = "0.6.0" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "1a8e2ac4e906dd26b25f7a9a7c7146cc27e670c793d5c34ef2b64b55f0135cd6" 222 | dependencies = [ 223 | "dioxus-core", 224 | "futures-channel", 225 | "futures-util", 226 | "generational-box", 227 | "once_cell", 228 | "parking_lot", 229 | "rustc-hash", 230 | "tracing", 231 | "warnings", 232 | ] 233 | 234 | [[package]] 235 | name = "dioxus-ssr" 236 | version = "0.6.0" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "e6cd3d309a60d654bafcf49b32b96fa72da6d9155582eba9b5c608c07ab0c850" 239 | dependencies = [ 240 | "askama_escape", 241 | "dioxus-core", 242 | "dioxus-core-types", 243 | "rustc-hash", 244 | ] 245 | 246 | [[package]] 247 | name = "enumset" 248 | version = "1.1.3" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" 251 | dependencies = [ 252 | "enumset_derive", 253 | ] 254 | 255 | [[package]] 256 | name = "enumset_derive" 257 | version = "0.8.1" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" 260 | dependencies = [ 261 | "darling", 262 | "proc-macro2", 263 | "quote", 264 | "syn", 265 | ] 266 | 267 | [[package]] 268 | name = "euclid" 269 | version = "0.22.10" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "e0f0eb73b934648cd7a4a61f1b15391cd95dab0b4da6e2e66c2a072c144b4a20" 272 | dependencies = [ 273 | "num-traits", 274 | ] 275 | 276 | [[package]] 277 | name = "fnv" 278 | version = "1.0.7" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 281 | 282 | [[package]] 283 | name = "futures-channel" 284 | version = "0.3.30" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 287 | dependencies = [ 288 | "futures-core", 289 | ] 290 | 291 | [[package]] 292 | name = "futures-core" 293 | version = "0.3.30" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 296 | 297 | [[package]] 298 | name = "futures-task" 299 | version = "0.3.30" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 302 | 303 | [[package]] 304 | name = "futures-util" 305 | version = "0.3.30" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 308 | dependencies = [ 309 | "futures-core", 310 | "futures-task", 311 | "pin-project-lite", 312 | "pin-utils", 313 | "slab", 314 | ] 315 | 316 | [[package]] 317 | name = "generational-box" 318 | version = "0.6.0" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "bbef36525d55a549ea17c1a33ddbd0dcfd153029e640c9eef845b24ae053dbed" 321 | dependencies = [ 322 | "parking_lot", 323 | "tracing", 324 | ] 325 | 326 | [[package]] 327 | name = "ident_case" 328 | version = "1.0.1" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 331 | 332 | [[package]] 333 | name = "keyboard-types" 334 | version = "0.7.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" 337 | dependencies = [ 338 | "bitflags", 339 | ] 340 | 341 | [[package]] 342 | name = "lazy-js-bundle" 343 | version = "0.6.0" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "703fcd40f2de720718e8b45a68bab510a4a8ee22484f75d0874b202f1eed5aa8" 346 | 347 | [[package]] 348 | name = "libc" 349 | version = "0.2.155" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 352 | 353 | [[package]] 354 | name = "lock_api" 355 | version = "0.4.12" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 358 | dependencies = [ 359 | "autocfg", 360 | "scopeguard", 361 | ] 362 | 363 | [[package]] 364 | name = "longest-increasing-subsequence" 365 | version = "0.1.0" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86" 368 | 369 | [[package]] 370 | name = "num-traits" 371 | version = "0.2.19" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 374 | dependencies = [ 375 | "autocfg", 376 | ] 377 | 378 | [[package]] 379 | name = "once_cell" 380 | version = "1.19.0" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 383 | 384 | [[package]] 385 | name = "parking_lot" 386 | version = "0.12.3" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 389 | dependencies = [ 390 | "lock_api", 391 | "parking_lot_core", 392 | ] 393 | 394 | [[package]] 395 | name = "parking_lot_core" 396 | version = "0.9.10" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 399 | dependencies = [ 400 | "cfg-if", 401 | "libc", 402 | "redox_syscall", 403 | "smallvec", 404 | "windows-targets", 405 | ] 406 | 407 | [[package]] 408 | name = "pin-project" 409 | version = "1.1.7" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" 412 | dependencies = [ 413 | "pin-project-internal", 414 | ] 415 | 416 | [[package]] 417 | name = "pin-project-internal" 418 | version = "1.1.7" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" 421 | dependencies = [ 422 | "proc-macro2", 423 | "quote", 424 | "syn", 425 | ] 426 | 427 | [[package]] 428 | name = "pin-project-lite" 429 | version = "0.2.14" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 432 | 433 | [[package]] 434 | name = "pin-utils" 435 | version = "0.1.0" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 438 | 439 | [[package]] 440 | name = "proc-macro2" 441 | version = "1.0.85" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" 444 | dependencies = [ 445 | "unicode-ident", 446 | ] 447 | 448 | [[package]] 449 | name = "proc-macro2-diagnostics" 450 | version = "0.10.1" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" 453 | dependencies = [ 454 | "proc-macro2", 455 | "quote", 456 | "syn", 457 | "version_check", 458 | ] 459 | 460 | [[package]] 461 | name = "quote" 462 | version = "1.0.36" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 465 | dependencies = [ 466 | "proc-macro2", 467 | ] 468 | 469 | [[package]] 470 | name = "redox_syscall" 471 | version = "0.5.1" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" 474 | dependencies = [ 475 | "bitflags", 476 | ] 477 | 478 | [[package]] 479 | name = "rustc-hash" 480 | version = "1.1.0" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 483 | 484 | [[package]] 485 | name = "rustversion" 486 | version = "1.0.18" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" 489 | 490 | [[package]] 491 | name = "scopeguard" 492 | version = "1.2.0" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 495 | 496 | [[package]] 497 | name = "serde" 498 | version = "1.0.203" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" 501 | dependencies = [ 502 | "serde_derive", 503 | ] 504 | 505 | [[package]] 506 | name = "serde_derive" 507 | version = "1.0.203" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" 510 | dependencies = [ 511 | "proc-macro2", 512 | "quote", 513 | "syn", 514 | ] 515 | 516 | [[package]] 517 | name = "slab" 518 | version = "0.4.9" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 521 | dependencies = [ 522 | "autocfg", 523 | ] 524 | 525 | [[package]] 526 | name = "slotmap" 527 | version = "1.0.7" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" 530 | dependencies = [ 531 | "serde", 532 | "version_check", 533 | ] 534 | 535 | [[package]] 536 | name = "smallvec" 537 | version = "1.13.2" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 540 | 541 | [[package]] 542 | name = "syn" 543 | version = "2.0.87" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" 546 | dependencies = [ 547 | "proc-macro2", 548 | "quote", 549 | "unicode-ident", 550 | ] 551 | 552 | [[package]] 553 | name = "tracing" 554 | version = "0.1.40" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 557 | dependencies = [ 558 | "pin-project-lite", 559 | "tracing-attributes", 560 | "tracing-core", 561 | ] 562 | 563 | [[package]] 564 | name = "tracing-attributes" 565 | version = "0.1.27" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 568 | dependencies = [ 569 | "proc-macro2", 570 | "quote", 571 | "syn", 572 | ] 573 | 574 | [[package]] 575 | name = "tracing-core" 576 | version = "0.1.32" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 579 | dependencies = [ 580 | "once_cell", 581 | ] 582 | 583 | [[package]] 584 | name = "unicode-ident" 585 | version = "1.0.12" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 588 | 589 | [[package]] 590 | name = "unicode-segmentation" 591 | version = "1.11.0" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" 594 | 595 | [[package]] 596 | name = "unicode-xid" 597 | version = "0.2.6" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 600 | 601 | [[package]] 602 | name = "version_check" 603 | version = "0.9.4" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 606 | 607 | [[package]] 608 | name = "warnings" 609 | version = "0.2.1" 610 | source = "registry+https://github.com/rust-lang/crates.io-index" 611 | checksum = "64f68998838dab65727c9b30465595c6f7c953313559371ca8bf31759b3680ad" 612 | dependencies = [ 613 | "pin-project", 614 | "tracing", 615 | "warnings-macro", 616 | ] 617 | 618 | [[package]] 619 | name = "warnings-macro" 620 | version = "0.2.0" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "59195a1db0e95b920366d949ba5e0d3fc0e70b67c09be15ce5abb790106b0571" 623 | dependencies = [ 624 | "proc-macro2", 625 | "quote", 626 | "syn", 627 | ] 628 | 629 | [[package]] 630 | name = "windows-targets" 631 | version = "0.52.5" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" 634 | dependencies = [ 635 | "windows_aarch64_gnullvm", 636 | "windows_aarch64_msvc", 637 | "windows_i686_gnu", 638 | "windows_i686_gnullvm", 639 | "windows_i686_msvc", 640 | "windows_x86_64_gnu", 641 | "windows_x86_64_gnullvm", 642 | "windows_x86_64_msvc", 643 | ] 644 | 645 | [[package]] 646 | name = "windows_aarch64_gnullvm" 647 | version = "0.52.5" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" 650 | 651 | [[package]] 652 | name = "windows_aarch64_msvc" 653 | version = "0.52.5" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" 656 | 657 | [[package]] 658 | name = "windows_i686_gnu" 659 | version = "0.52.5" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" 662 | 663 | [[package]] 664 | name = "windows_i686_gnullvm" 665 | version = "0.52.5" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" 668 | 669 | [[package]] 670 | name = "windows_i686_msvc" 671 | version = "0.52.5" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" 674 | 675 | [[package]] 676 | name = "windows_x86_64_gnu" 677 | version = "0.52.5" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" 680 | 681 | [[package]] 682 | name = "windows_x86_64_gnullvm" 683 | version = "0.52.5" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" 686 | 687 | [[package]] 688 | name = "windows_x86_64_msvc" 689 | version = "0.52.5" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" 692 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "daisy_rsx" 3 | version = "0.1.14" 4 | edition = "2021" 5 | description = "Daisy UI components for the Dioxus Rust library." 6 | license = "MIT" 7 | repository = "https://github.com/bionic-gpt/daisy-rsx/" 8 | homepage = "https://github.com/bionic-gpt/daisy-rsx" 9 | 10 | [lib] 11 | path = "src/lib.rs" 12 | 13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 | 15 | [dependencies] 16 | dioxus = { version = "0.6", default-features = false, features = ["macro", "html", "signals"] } 17 | dioxus-ssr = { version = "0.6", default-features = false } 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 bionic-gpt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Daisy-RSX 2 | 3 | This is a [Dioxus](https://dioxuslabs.com/) version of the [Daisy UI](https://daisyui.com/) components. 4 | 5 | ## To Create a Release 6 | 7 | To create a new release, use the following command locally: 8 | 9 | ```sh 10 | cargo release patch 11 | ``` 12 | 13 | Once you are ready, pass the `--execute` flag. 14 | 15 | This will: 16 | 17 | - Bump the version number. 18 | - Create a git tag. 19 | - Push changes to the remote repository. 20 | - Trigger the GitHub Actions workflow to publish the crate. -------------------------------------------------------------------------------- /src/accordian.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(unused_braces)] 3 | 4 | use dioxus::prelude::*; 5 | 6 | #[derive(Props, Clone, PartialEq)] 7 | pub struct AccordianProps { 8 | name: String, 9 | title: String, 10 | checked: Option, 11 | children: Element, 12 | } 13 | 14 | #[component] 15 | pub fn Accordian(props: AccordianProps) -> Element { 16 | rsx!( 17 | div { 18 | class: "collapse collapse-arrow bg-base-200", 19 | input { 20 | checked: props.checked, 21 | "type": "radio", 22 | name: props.name 23 | } 24 | div { 25 | class: "collapse-title text-md font-medium", 26 | "{props.title}" 27 | } 28 | div { 29 | class: "collapse-content bg-base-200", 30 | {{props.children}} 31 | } 32 | } 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /src/alert.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] 5 | pub enum AlertColor { 6 | #[default] 7 | Default, 8 | Warn, 9 | Info, 10 | Error, 11 | Success, 12 | } 13 | 14 | impl AlertColor { 15 | pub fn to_string(&self) -> &'static str { 16 | match self { 17 | AlertColor::Default => "alert alert-info", 18 | AlertColor::Info => "alert alert-info", 19 | AlertColor::Warn => "alert alert-warning", 20 | AlertColor::Error => "alert alert-error", 21 | AlertColor::Success => "alert alert-success", 22 | } 23 | } 24 | } 25 | 26 | #[derive(Props, Clone, PartialEq)] 27 | pub struct AlertProps { 28 | children: Element, 29 | class: Option, 30 | alert_color: Option, 31 | } 32 | 33 | #[component] 34 | pub fn Alert(props: AlertProps) -> Element { 35 | let alert_color = if props.alert_color.is_some() { 36 | props.alert_color.unwrap() 37 | } else { 38 | Default::default() 39 | }; 40 | 41 | let class = if let Some(class) = props.class { 42 | class 43 | } else { 44 | "".to_string() 45 | }; 46 | 47 | let class = format!("{} {}", alert_color.to_string(), class); 48 | 49 | rsx!( 50 | div { 51 | class: "{class}", 52 | {props.children}, 53 | } 54 | ) 55 | } 56 | -------------------------------------------------------------------------------- /src/app_layout.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Props, Clone, PartialEq)] 5 | pub struct AppLayoutProps { 6 | title: String, 7 | fav_icon_src: Option, 8 | stylesheets: Vec, 9 | js_href: Option, 10 | header: Element, 11 | children: Element, 12 | sidebar: Element, 13 | sidebar_footer: Element, 14 | sidebar_header: Element, 15 | } 16 | 17 | pub fn AppLayout(props: AppLayoutProps) -> Element { 18 | rsx!( 19 | head { 20 | title { 21 | "{props.title}" 22 | } 23 | meta { 24 | charset: "utf-8" 25 | } 26 | meta { 27 | "http-equiv": "X-UA-Compatible", 28 | content: "IE=edge" 29 | } 30 | meta { 31 | name: "viewport", 32 | content: "width=device-width, initial-scale=1" 33 | } 34 | for href in &props.stylesheets { 35 | link { 36 | rel: "stylesheet", 37 | href: "{href}", 38 | "type": "text/css" 39 | } 40 | } 41 | if let Some(js_href) = props.js_href { 42 | script { 43 | "type": "module", 44 | src: "{js_href}" 45 | } 46 | } 47 | if let Some(fav_icon_src) = props.fav_icon_src { 48 | link { 49 | rel: "icon", 50 | "type": "image/svg+xml", 51 | href: "{fav_icon_src}" 52 | } 53 | } 54 | } 55 | body { 56 | div { 57 | class: "flex h-screen overflow-hidden", 58 | nav { 59 | id: "sidebar", 60 | class: " 61 | border-r border-base-300 62 | fixed 63 | bg-base-200 64 | inset-y-0 65 | left-0 66 | w-64 67 | transform 68 | -translate-x-full 69 | transition-transform 70 | duration-200 71 | ease-in-out 72 | flex 73 | flex-col 74 | lg:translate-x-0 75 | lg:static 76 | lg:inset-auto 77 | lg:transform-none 78 | z-20", 79 | div { 80 | class: "flex items-center p-4", 81 | {props.sidebar_header} 82 | } 83 | div { 84 | class: "flex-1 overflow-y-auto", 85 | {props.sidebar} 86 | } 87 | div { 88 | class: "p-4", 89 | {props.sidebar_footer} 90 | } 91 | } 92 | main { 93 | id: "main-content", 94 | class: "flex-1 flex flex-col", 95 | header { 96 | class: "flex items-center p-4 border-b border-base-300", 97 | button { 98 | id: "toggleButton", 99 | svg { 100 | xmlns: "http://www.w3.org/2000/svg", 101 | width: "24", 102 | height: "24", 103 | view_box: "0 0 24 24", 104 | fill: "none", 105 | stroke: "currentColor", 106 | stroke_width: "2", 107 | stroke_linecap: "round", 108 | stroke_linejoin: "round", 109 | class: "lucide lucide-panel-left", 110 | rect { 111 | width: "18", 112 | height: "18", 113 | x: "3", 114 | y: "3", 115 | rx: "2", 116 | } 117 | path { 118 | d: "M9 3v18", 119 | } 120 | } 121 | } 122 | {props.header} 123 | } 124 | section { 125 | class: "flex-1 overflow-y-auto", 126 | {props.children} 127 | } 128 | } 129 | } 130 | } 131 | ) 132 | } -------------------------------------------------------------------------------- /src/avatar.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(unused_braces)] 3 | use dioxus::prelude::*; 4 | 5 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 6 | pub enum AvatarType { 7 | Team, 8 | #[default] 9 | User, 10 | } 11 | 12 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 13 | pub enum AvatarSize { 14 | #[default] 15 | Small, 16 | Medium, 17 | Large, 18 | ExtraLarge, 19 | } 20 | 21 | impl AvatarSize { 22 | pub fn to_string(&self) -> (&'static str, &'static str, &'static str) { 23 | match self { 24 | AvatarSize::Small => ("24", "24", "w-8 h-8"), 25 | AvatarSize::Medium => ("48", "48", "w-16 h-16"), 26 | AvatarSize::Large => ("96", "96", "w-20 w-20"), 27 | AvatarSize::ExtraLarge => ("128", "128", "w-32 h-32"), 28 | } 29 | } 30 | } 31 | 32 | #[derive(Props, Clone, PartialEq)] 33 | pub struct AvatarProps { 34 | avatar_size: Option, 35 | avatar_type: Option, 36 | name: Option, 37 | _email: Option, 38 | image_src: Option, 39 | } 40 | 41 | #[component] 42 | pub fn Avatar(props: AvatarProps) -> Element { 43 | let avatar_size = if props.avatar_size.is_some() { 44 | props.avatar_size.unwrap() 45 | } else { 46 | Default::default() 47 | }; 48 | let avatar_size = avatar_size.to_string(); 49 | 50 | let mut the_name = "?".to_string(); 51 | if let Some(name) = props.name { 52 | the_name = if let Some(chr) = name.chars().next() { 53 | chr.to_string() 54 | } else { 55 | "?".to_string() 56 | }; 57 | } 58 | 59 | if let Some(image) = props.image_src { 60 | rsx!( 61 | div { 62 | class: "avatar", 63 | div { 64 | class: "rounded {avatar_size.2}", 65 | img { 66 | width: avatar_size.0, 67 | height: avatar_size.1, 68 | src: image 69 | } 70 | } 71 | } 72 | ) 73 | } else { 74 | match props.avatar_type { 75 | Some(AvatarType::User) => rsx!( 76 | div { 77 | class: "avatar", 78 | div { 79 | class: "rounded {avatar_size.2}", 80 | svg { 81 | "aria-hidden": true, 82 | xmlns: "http://www.w3.org/2000/svg", 83 | height: avatar_size.0, 84 | width: avatar_size.1, 85 | "viewbox": "0 0 27 27", 86 | rect { 87 | fill: "rgb(125, 73, 193)", 88 | height: "27", 89 | rx: "12", 90 | width: "27", 91 | x: "0", 92 | y: "0" 93 | } 94 | g { 95 | fill: "#fff", 96 | opacity: ".5", 97 | circle { 98 | cx: "13.5", 99 | cy: "30", 100 | r: "13" 101 | } 102 | circle { 103 | cx: "13.5", 104 | cy: "11", 105 | r: "5" 106 | } 107 | } 108 | } 109 | } 110 | } 111 | ), 112 | Some(_) => rsx!( 113 | div { 114 | class: "avatar", 115 | div { 116 | class: "rounded {avatar_size.2}", 117 | svg { 118 | "aria-hidden": true, 119 | xmlns: "http://www.w3.org/2000/svg", 120 | "viewBox": "0 0 50 50", 121 | height: avatar_size.0, 122 | width: avatar_size.1, 123 | rect { 124 | fill: "rgb(46, 77, 172)", 125 | height: "100%", 126 | width: "100%", 127 | } 128 | text { 129 | fill: "#fff", 130 | "font-size": "26", 131 | "font-weight": "500", 132 | x: "50%", 133 | y: "55%", 134 | "dominant-baseline": "middle", 135 | "text-anchor": "middle", 136 | {the_name} 137 | } 138 | } 139 | } 140 | } 141 | ), 142 | None => rsx!( 143 | div { 144 | class: "avatar", 145 | div { 146 | class: "rounded {avatar_size.2}", 147 | svg { 148 | "aria-hidden": true, 149 | xmlns: "http://www.w3.org/2000/svg", 150 | "viewBox": "0 0 50 50", 151 | height: avatar_size.0, 152 | width: avatar_size.1, 153 | rect { 154 | fill: "rgb(46, 77, 172)", 155 | height: "100%", 156 | width: "100%", 157 | } 158 | text { 159 | fill: "#fff", 160 | "font-size": "26", 161 | "font-weight": "500", 162 | x: "50%", 163 | y: "55%", 164 | "dominant-baseline": "middle", 165 | "text-anchor": "middle", 166 | {the_name} 167 | } 168 | } 169 | } 170 | } 171 | ), 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/blank_slate.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use super::button::{Button, ButtonScheme}; 3 | use dioxus::prelude::*; 4 | 5 | #[derive(Props, Clone, PartialEq)] 6 | pub struct BlankSlateProps { 7 | heading: String, 8 | visual: String, 9 | description: String, 10 | primary_action: Option<(String, String)>, 11 | primary_action_drawer: Option<(String, String)>, 12 | secondary_action: Option<(String, String)>, 13 | } 14 | 15 | #[component] 16 | pub fn BlankSlate(props: BlankSlateProps) -> Element { 17 | rsx!( 18 | div { 19 | class: "mt-4 flex flex-col justify-center items-center", 20 | img { 21 | class: "mb-4 svg-icon", 22 | src: "{props.visual}", 23 | width: "100px" 24 | } 25 | h2 { 26 | class: "text-center mb-4 max-w-prose", 27 | "{props.heading}" 28 | } 29 | p { 30 | class: "mb-4 max-w-prose text-center", 31 | "{props.description}" 32 | } 33 | match &props.primary_action { 34 | Some(pa) => rsx!( 35 | div { 36 | a { 37 | href: "{pa.1}", 38 | span { 39 | class: "Button-label", 40 | "{pa.0}" 41 | } 42 | } 43 | } 44 | ), 45 | None => rsx!() 46 | } 47 | match props.primary_action_drawer { 48 | Some(pa) => rsx!( 49 | div { 50 | Button { 51 | button_scheme: ButtonScheme::Primary, 52 | drawer_trigger: "{pa.1}", 53 | "{pa.0}" 54 | } 55 | } 56 | ), 57 | None => rsx!() 58 | } 59 | match props.secondary_action { 60 | Some(pa) => rsx!( 61 | div { 62 | a { 63 | href: "{pa.1}", 64 | "{pa.0}" 65 | } 66 | } 67 | ), 68 | None => rsx!() 69 | } 70 | } 71 | ) 72 | } 73 | -------------------------------------------------------------------------------- /src/button.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 5 | pub enum ButtonScheme { 6 | #[default] 7 | Default, 8 | Primary, 9 | Outline, 10 | Danger, 11 | } 12 | 13 | impl ButtonScheme { 14 | pub fn to_string(&self) -> &'static str { 15 | match self { 16 | ButtonScheme::Default => "btn-default", 17 | ButtonScheme::Primary => "btn-primary", 18 | ButtonScheme::Outline => "btn-outline", 19 | ButtonScheme::Danger => "btn-warning", 20 | } 21 | } 22 | } 23 | 24 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 25 | pub enum ButtonType { 26 | Submit, 27 | Reset, 28 | #[default] 29 | Button, 30 | } 31 | 32 | impl ButtonType { 33 | pub fn to_string(&self) -> &'static str { 34 | match self { 35 | ButtonType::Submit => "submit", 36 | ButtonType::Reset => "reset", 37 | ButtonType::Button => "button", 38 | } 39 | } 40 | } 41 | 42 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 43 | pub enum ButtonSize { 44 | #[default] 45 | Default, 46 | Small, 47 | ExtraSmall, 48 | Large, 49 | Medium, 50 | } 51 | 52 | impl ButtonSize { 53 | pub fn to_string(&self) -> &'static str { 54 | match self { 55 | ButtonSize::Default => "btn-sm", 56 | ButtonSize::ExtraSmall => "btn-xs", 57 | ButtonSize::Small => "btn-sm", 58 | ButtonSize::Medium => "btn-md", 59 | ButtonSize::Large => "btn-lg", 60 | } 61 | } 62 | } 63 | 64 | #[derive(Props, Clone, PartialEq)] 65 | pub struct ButtonProps { 66 | children: Element, 67 | id: Option, 68 | disabled: Option, 69 | class: Option, 70 | prefix_image_src: Option, 71 | suffix_image_src: Option, 72 | button_type: Option, 73 | button_size: Option, 74 | button_scheme: Option, 75 | drawer_trigger: Option, 76 | modal_trigger: Option, 77 | disabled_text: Option, 78 | } 79 | 80 | #[component] 81 | pub fn Button(props: ButtonProps) -> Element { 82 | let button_scheme = if props.button_scheme.is_some() { 83 | props.button_scheme.unwrap() 84 | } else { 85 | Default::default() 86 | }; 87 | 88 | let button_type = if props.button_type.is_some() { 89 | props.button_type.unwrap() 90 | } else { 91 | Default::default() 92 | }; 93 | let button_type = button_type.to_string(); 94 | 95 | let button_size = if props.button_size.is_some() { 96 | props.button_size.unwrap() 97 | } else { 98 | Default::default() 99 | }; 100 | 101 | let class = if let Some(class) = props.class { 102 | class 103 | } else { 104 | "".to_string() 105 | }; 106 | 107 | let disabled = if let Some(disabled) = props.disabled { 108 | if disabled { 109 | Some(true) 110 | } else { 111 | None 112 | } 113 | } else { 114 | None 115 | }; 116 | 117 | let class = format!( 118 | "btn {} {} {}", 119 | class, 120 | button_scheme.to_string(), 121 | button_size.to_string() 122 | ); 123 | 124 | rsx!( 125 | button { 126 | class: "{class}", 127 | id: props.id, 128 | disabled: disabled, 129 | "data-drawer-target": props.drawer_trigger, 130 | "data-modal-target": props.modal_trigger, 131 | "type": "{button_type}", 132 | "data-disabled-text": props.disabled_text, 133 | if let Some(img_src) = props.prefix_image_src { 134 | img { 135 | src: "{img_src}", 136 | class: "mr-2", 137 | width: "12" 138 | } 139 | }, 140 | {props.children}, 141 | if let Some(img_src) = props.suffix_image_src { 142 | img { 143 | src: "{img_src}", 144 | class: "ml-2", 145 | width: "12" 146 | } 147 | } 148 | } 149 | ) 150 | } 151 | -------------------------------------------------------------------------------- /src/card.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use dioxus::prelude::*; 4 | 5 | #[derive(Props, Clone, PartialEq)] 6 | pub struct CardProps { 7 | class: Option, 8 | children: Element, 9 | drawer_trigger: Option, 10 | modal_trigger: Option, 11 | } 12 | 13 | #[component] 14 | pub fn Card(props: CardProps) -> Element { 15 | let class = if let Some(class) = props.class { 16 | class 17 | } else { 18 | "".to_string() 19 | }; 20 | 21 | let class = format!("card {}", class); 22 | 23 | rsx!( 24 | div { 25 | class: "{class}", 26 | "data-drawer-target": props.drawer_trigger, 27 | "data-modal-target": props.modal_trigger, 28 | {props.children} 29 | } 30 | ) 31 | } 32 | 33 | #[derive(Props, Clone, PartialEq)] 34 | pub struct CardHeadersProps { 35 | class: Option, 36 | title: String, 37 | children: Element, 38 | } 39 | 40 | #[component] 41 | pub fn CardHeader(props: CardHeadersProps) -> Element { 42 | let class = if let Some(class) = props.class { 43 | class 44 | } else { 45 | "".to_string() 46 | }; 47 | 48 | let class = format!("card-header flex items-center {}", class); 49 | 50 | rsx!( 51 | div { 52 | class: "{class}", 53 | h3 { 54 | class: "card-title overflow-hidden", 55 | "{props.title}" 56 | } 57 | {props.children} 58 | } 59 | ) 60 | } 61 | 62 | #[derive(Props, Clone, PartialEq)] 63 | pub struct CardBodyProps { 64 | class: Option, 65 | children: Element, 66 | } 67 | 68 | #[component] 69 | pub fn CardBody(props: CardBodyProps) -> Element { 70 | let class = if let Some(class) = props.class { 71 | format!("card-body {}", class) 72 | } else { 73 | "card-body".to_string() 74 | }; 75 | 76 | rsx!( 77 | div { 78 | class: "{class}", 79 | {props.children} 80 | } 81 | ) 82 | } 83 | -------------------------------------------------------------------------------- /src/check_box.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 5 | pub enum CheckBoxScheme { 6 | #[default] 7 | Default, 8 | Primary, 9 | Outline, 10 | Danger, 11 | } 12 | 13 | impl CheckBoxScheme { 14 | pub fn to_string(&self) -> &'static str { 15 | match self { 16 | CheckBoxScheme::Default => "checkbox-default", 17 | CheckBoxScheme::Primary => "checkbox-primary", 18 | CheckBoxScheme::Outline => "checkbox-outline", 19 | CheckBoxScheme::Danger => "checkbox-warning", 20 | } 21 | } 22 | } 23 | 24 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 25 | pub enum CheckBoxSize { 26 | #[default] 27 | Default, 28 | Small, 29 | ExtraSmall, 30 | Large, 31 | Medium, 32 | } 33 | 34 | impl CheckBoxSize { 35 | pub fn to_string(&self) -> &'static str { 36 | match self { 37 | CheckBoxSize::Default => "checkbox-sm", 38 | CheckBoxSize::ExtraSmall => "checkbox-xs", 39 | CheckBoxSize::Small => "checkbox-sm", 40 | CheckBoxSize::Medium => "checkbox-md", 41 | CheckBoxSize::Large => "checkbox-lg", 42 | } 43 | } 44 | } 45 | 46 | #[derive(Props, Clone, PartialEq)] 47 | pub struct CheckBoxProps { 48 | children: Element, 49 | id: Option, 50 | checked: Option, 51 | class: Option, 52 | name: String, 53 | value: String, 54 | checkbox_size: Option, 55 | checkbox_scheme: Option, 56 | } 57 | 58 | #[component] 59 | pub fn CheckBox(props: CheckBoxProps) -> Element { 60 | let checkbox_scheme = if props.checkbox_scheme.is_some() { 61 | props.checkbox_scheme.unwrap() 62 | } else { 63 | Default::default() 64 | }; 65 | 66 | let checkbox_size = if props.checkbox_size.is_some() { 67 | props.checkbox_size.unwrap() 68 | } else { 69 | Default::default() 70 | }; 71 | 72 | let class = if let Some(class) = props.class { 73 | class 74 | } else { 75 | "".to_string() 76 | }; 77 | 78 | let checked = if let Some(checked) = props.checked { 79 | if checked { 80 | Some("checked") 81 | } else { 82 | None 83 | } 84 | } else { 85 | None 86 | }; 87 | 88 | let class = format!( 89 | "checkbox {} {} {}", 90 | class, 91 | checkbox_scheme.to_string(), 92 | checkbox_size.to_string() 93 | ); 94 | 95 | rsx!( 96 | input { 97 | "type": "checkbox", 98 | class: "{class}", 99 | id: props.id, 100 | name: props.name, 101 | value: props.value, 102 | checked: checked, 103 | {props.children}, 104 | } 105 | ) 106 | } 107 | -------------------------------------------------------------------------------- /src/drawer.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use dioxus::prelude::*; 4 | 5 | #[derive(Props, Clone, PartialEq)] 6 | pub struct DrawerProps { 7 | trigger_id: String, 8 | label: String, 9 | children: Element, 10 | submit_action: Option, 11 | } 12 | 13 | #[component] 14 | pub fn Drawer(props: DrawerProps) -> Element { 15 | if let Some(action) = &props.submit_action { 16 | rsx!( 17 | form { 18 | action: "{action}", 19 | method: "post", 20 | div { 21 | div { 22 | class: "side-drawer flex flex-col", 23 | id: props.trigger_id, 24 | div { 25 | class: "drawer__overlay", 26 | tabindex: "-1" 27 | } 28 | div { 29 | class: "drawer__panel", 30 | header { 31 | class: "drawer__header", 32 | h4 { 33 | class: "drawer__title", 34 | "{props.label}" 35 | } 36 | a { 37 | href: "#", 38 | class: "drawer__close", 39 | "X" 40 | } 41 | } 42 | {props.children} 43 | } 44 | } 45 | } 46 | } 47 | ) 48 | } else { 49 | rsx!( 50 | div { 51 | div { 52 | class: "side-drawer flex flex-col", 53 | id: props.trigger_id, 54 | div { 55 | class: "drawer__overlay", 56 | tabindex: "-1" 57 | } 58 | div { 59 | class: "drawer__panel", 60 | header { 61 | class: "drawer__header", 62 | h4 { 63 | class: "drawer__title", 64 | "{props.label}" 65 | } 66 | a { 67 | href: "#", 68 | class: "drawer__close", 69 | "X" 70 | } 71 | } 72 | {props.children} 73 | } 74 | } 75 | } 76 | ) 77 | } 78 | } 79 | 80 | #[derive(Props, Clone, PartialEq)] 81 | pub struct DrawerFooterProps { 82 | children: Element, 83 | } 84 | 85 | #[component] 86 | pub fn DrawerFooter(props: DrawerFooterProps) -> Element { 87 | rsx!( 88 | div { 89 | class: "drawer__footer", 90 | {props.children} 91 | } 92 | ) 93 | } 94 | 95 | #[derive(Props, Clone, PartialEq)] 96 | pub struct DrawerBodyProps { 97 | children: Element, 98 | class: Option, 99 | } 100 | 101 | #[component] 102 | pub fn DrawerBody(props: DrawerBodyProps) -> Element { 103 | let class = if let Some(class) = props.class { 104 | class 105 | } else { 106 | "".to_string() 107 | }; 108 | 109 | let class = format!("drawer__body {}", class); 110 | rsx!( 111 | div { 112 | class: "{class}", 113 | {props.children} 114 | } 115 | ) 116 | } 117 | -------------------------------------------------------------------------------- /src/drop_down.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 5 | pub enum Direction { 6 | #[default] 7 | None, 8 | Top, 9 | Bottom, 10 | Left, 11 | Right, 12 | } 13 | 14 | impl Direction { 15 | pub fn to_string(&self) -> &'static str { 16 | match self { 17 | Direction::None => "", 18 | Direction::Top => "dropdown-top", 19 | Direction::Bottom => "dropdown-bottom", 20 | Direction::Left => "dropdown-left", 21 | Direction::Right => "dropdown-right", 22 | } 23 | } 24 | } 25 | 26 | #[derive(Props, Clone, PartialEq)] 27 | pub struct DropDownProps { 28 | children: Element, 29 | carat: Option, 30 | button_text: String, 31 | class: Option, 32 | direction: Option, 33 | prefix_image_src: Option, 34 | suffix_image_src: Option, 35 | } 36 | 37 | #[component] 38 | pub fn DropDown(props: DropDownProps) -> Element { 39 | let direction = if let Some(direction) = props.direction { 40 | direction.to_string() 41 | } else { 42 | Direction::default().to_string() 43 | }; 44 | 45 | let class = if let Some(class) = props.class { 46 | class 47 | } else { 48 | "".to_string() 49 | }; 50 | 51 | rsx!( 52 | div { 53 | class: "dropdown {class} {direction}", 54 | label { 55 | tabindex: "0", 56 | class: "btn btn-default btn-sm m-1 w-full flex flex-nowrap justify-between", 57 | "aria-haspopup": "true", 58 | if let Some(img_src) = props.prefix_image_src { 59 | img { 60 | src: "{img_src}", 61 | class: "mr-2", 62 | width: "16" 63 | } 64 | }, 65 | span { 66 | class: "truncate", 67 | "{props.button_text}" 68 | } 69 | if let Some(img_src) = props.suffix_image_src { 70 | img { 71 | src: "{img_src}", 72 | class: "ml-2", 73 | width: "12" 74 | } 75 | } else if props.carat.is_some() && props.carat.unwrap() { 76 | div { 77 | class: "dropdown-caret" 78 | } 79 | } 80 | } 81 | ul { 82 | tabindex: "0", 83 | class: "dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52 {direction}", 84 | {props.children}, 85 | } 86 | } 87 | ) 88 | } 89 | 90 | #[derive(Props, Clone, PartialEq)] 91 | pub struct DropDownLinkProps { 92 | href: String, 93 | target: Option, 94 | drawer_trigger: Option, 95 | class: Option, 96 | children: Element, 97 | } 98 | 99 | #[component] 100 | pub fn DropDownLink(props: DropDownLinkProps) -> Element { 101 | let class = if let Some(class) = props.class { 102 | format!("dropdown-item {} ", class) 103 | } else { 104 | "dropdown-item".to_string() 105 | }; 106 | 107 | if let Some(trigger) = &props.drawer_trigger { 108 | rsx!( 109 | li { 110 | a { 111 | class: "{class}", 112 | "data-drawer-target": "{trigger}", 113 | target: props.target, 114 | href: "{props.href}", 115 | {props.children}, 116 | } 117 | } 118 | ) 119 | } else { 120 | rsx!( 121 | li { 122 | a { 123 | class: "{class}", 124 | target: props.target, 125 | href: "{props.href}", 126 | {props.children}, 127 | } 128 | } 129 | ) 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/input.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 5 | pub enum InputType { 6 | #[default] 7 | Text, 8 | Number, 9 | Email, 10 | Password, 11 | } 12 | 13 | impl InputType { 14 | pub fn to_string(&self) -> &'static str { 15 | match self { 16 | InputType::Text => "text", 17 | InputType::Number => "number", 18 | InputType::Email => "email", 19 | InputType::Password => "password", 20 | } 21 | } 22 | } 23 | 24 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 25 | pub enum InputSize { 26 | #[default] 27 | Default, 28 | Small, 29 | ExtraSmall, 30 | Large, 31 | Medium, 32 | } 33 | 34 | impl InputSize { 35 | pub fn to_string(&self) -> &'static str { 36 | match self { 37 | InputSize::Default => "input-sm", 38 | InputSize::ExtraSmall => "input-xs", 39 | InputSize::Small => "input-sm", 40 | InputSize::Large => "input-lg", 41 | InputSize::Medium => "input-md", 42 | } 43 | } 44 | } 45 | 46 | #[derive(Props, Clone, PartialEq)] 47 | pub struct InputProps { 48 | input_type: Option, 49 | input_size: Option, 50 | pub name: String, 51 | pub id: Option, 52 | pub label_class: Option, 53 | pub value: Option, 54 | pub label: Option, 55 | pub help_text: Option, 56 | pub placeholder: Option, 57 | pub step: Option, 58 | pub required: Option, 59 | pub disabled: Option, 60 | pub readonly: Option, 61 | } 62 | 63 | #[component] 64 | pub fn Input(props: InputProps) -> Element { 65 | let input_type = if props.input_type.is_some() { 66 | props.input_type.unwrap() 67 | } else { 68 | Default::default() 69 | }; 70 | 71 | let input_size = if props.input_size.is_some() { 72 | props.input_size.unwrap() 73 | } else { 74 | Default::default() 75 | }; 76 | 77 | let input_type = input_type.to_string(); 78 | let input_size = input_size.to_string(); 79 | 80 | let input_class = format!("{} {}", input_type, input_size); 81 | 82 | rsx!( 83 | match (props.label, props.required) { 84 | (Some(l), Some(_)) => rsx!( 85 | label { 86 | class: props.label_class, 87 | "{l} *" 88 | } 89 | ), 90 | (Some(l), None) => rsx!( 91 | label { 92 | class: props.label_class, 93 | "{l}" 94 | } 95 | ), 96 | (None, _) => rsx!() 97 | } 98 | input { 99 | id: props.id, 100 | class: "input input-bordered {input_class}", 101 | value: props.value, 102 | required: props.required, 103 | disabled: props.disabled, 104 | readonly: props.readonly, 105 | name: "{props.name}", 106 | placeholder: props.placeholder, 107 | step: props.step, 108 | "type": "{input_type}" 109 | } 110 | if let Some(l) = props.help_text { 111 | label { 112 | span { 113 | class: "label-text-alt", 114 | "{l}" 115 | } 116 | } 117 | } 118 | ) 119 | } 120 | -------------------------------------------------------------------------------- /src/label.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 5 | pub enum LabelRole { 6 | #[default] 7 | Neutral, 8 | Danger, 9 | Warning, 10 | Success, 11 | Info, 12 | Highlight, 13 | } 14 | 15 | impl LabelRole { 16 | pub fn to_string(&self) -> &'static str { 17 | match self { 18 | LabelRole::Neutral => "label-neutral", 19 | LabelRole::Danger => "label-danger", 20 | LabelRole::Warning => "label-warning", 21 | LabelRole::Success => "label-success", 22 | LabelRole::Info => "label-info", 23 | LabelRole::Highlight => "label-highlight", 24 | } 25 | } 26 | } 27 | 28 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 29 | pub enum LabelSize { 30 | #[default] 31 | Small, 32 | Large, 33 | } 34 | 35 | impl LabelSize { 36 | pub fn to_string(&self) -> &'static str { 37 | match self { 38 | LabelSize::Small => "", 39 | LabelSize::Large => "badge-lg", 40 | } 41 | } 42 | } 43 | 44 | #[derive(Props, Clone, PartialEq)] 45 | pub struct LabelProps { 46 | children: Element, 47 | class: Option, 48 | label_role: Option, 49 | label_size: Option, 50 | } 51 | 52 | #[component] 53 | pub fn Label(props: LabelProps) -> Element { 54 | let label_role = if props.label_role.is_some() { 55 | props.label_role.unwrap() 56 | } else { 57 | Default::default() 58 | }; 59 | 60 | let label_size = if props.label_size.is_some() { 61 | props.label_size.unwrap() 62 | } else { 63 | Default::default() 64 | }; 65 | 66 | let class = if let Some(class) = props.class { 67 | class 68 | } else { 69 | "".to_string() 70 | }; 71 | 72 | let class = format!( 73 | "badge {} {} {}", 74 | label_role.to_string(), 75 | label_size.to_string(), 76 | class 77 | ); 78 | 79 | rsx!( 80 | button { 81 | class: "{class}", 82 | {props.children}, 83 | } 84 | ) 85 | } 86 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod accordian; 2 | pub mod alert; 3 | pub mod app_layout; 4 | pub mod avatar; 5 | pub mod blank_slate; 6 | pub mod button; 7 | pub mod card; 8 | pub mod check_box; 9 | pub mod drawer; 10 | pub mod drop_down; 11 | pub mod input; 12 | pub mod label; 13 | pub mod marketing; 14 | pub mod modal; 15 | pub mod nav_item; 16 | pub mod pagination; 17 | pub mod range; 18 | pub mod relative_time; 19 | pub mod select; 20 | pub mod tab_container; 21 | pub mod text_area; 22 | pub mod time_line; 23 | pub mod tooltip; 24 | 25 | pub use accordian::Accordian; 26 | pub use alert::{Alert, AlertColor}; 27 | pub use app_layout::AppLayout; 28 | pub use avatar::{Avatar, AvatarSize, AvatarType}; 29 | pub use blank_slate::BlankSlate; 30 | pub use button::{Button, ButtonScheme, ButtonSize, ButtonType}; 31 | pub use card::{Card, CardBody, CardHeader}; 32 | pub use check_box::{CheckBox, CheckBoxScheme, CheckBoxSize}; 33 | pub use drawer::{Drawer, DrawerBody, DrawerFooter}; 34 | pub use drop_down::{Direction, DropDown, DropDownLink}; 35 | pub use input::{Input, InputSize, InputType}; 36 | pub use label::{Label, LabelRole, LabelSize}; 37 | pub use modal::{Modal, ModalAction, ModalBody}; 38 | pub use nav_item::{NavGroup, NavItem, NavSubGroup, NavSubItem}; 39 | pub use pagination::Pagination; 40 | pub use range::{Range, RangeColor}; 41 | pub use relative_time::{RelativeTime, RelativeTimeFormat}; 42 | pub use select::{Select, SelectOption, SelectSize}; 43 | pub use tab_container::{TabContainer, TabPanel}; 44 | pub use text_area::{TextArea, TextAreaSize}; 45 | pub use time_line::{TimeLine, TimeLineBadge, TimeLineBody}; 46 | pub use tooltip::{ToolTip, ToolTipColor}; 47 | -------------------------------------------------------------------------------- /src/marketing/benefits.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn Benefits( 5 | title: String, 6 | subtitle: String, 7 | benefit1: String, 8 | benefit1_desc: String, 9 | benefit2: String, 10 | benefit2_desc: String, 11 | benefit3: String, 12 | benefit3_desc: String, 13 | class: Option, 14 | ) -> Element { 15 | rsx! { 16 | section { 17 | class: format!("lg:max-w-5xl {}", class.unwrap_or("".to_string())), 18 | div { 19 | class: "container mx-auto", 20 | div { 21 | class: "flex flex-col text-center w-full mb-20", 22 | h2 { 23 | class: "text-primary tracking-widest font-medium title-font mb-1", 24 | "{title}" 25 | } 26 | h1 { 27 | class: "sm:text-3xl text-2xl font-medium title-font text-primary", 28 | "{subtitle}" 29 | } 30 | } 31 | div { 32 | class: "flex flex-wrap -m-4", 33 | div { 34 | class: "p-4 md:w-1/3", 35 | div { 36 | class: "flex rounded-lg h-full bg-base-200 p-8 flex-col", 37 | div { 38 | class: "flex items-center mb-3", 39 | div { 40 | class: "w-8 h-8 mr-3 inline-flex items-center justify-center rounded-full bg-indigo-500 text-white flex-shrink-0", 41 | svg { 42 | fill: "none", 43 | stroke: "currentColor", 44 | stroke_linecap: "round", 45 | stroke_linejoin: "round", 46 | stroke_width: "2", 47 | class: "w-5 h-5", 48 | view_box: "0 0 24 24", 49 | path { d: "M22 12h-4l-3 9L9 3l-3 9H2" } 50 | } 51 | } 52 | h2 { 53 | class: "text-lg title-font font-medium", 54 | "{benefit1}" 55 | } 56 | } 57 | div { 58 | class: "flex-grow", 59 | p { 60 | class: "leading-relaxed text-base", 61 | "{benefit1_desc}" 62 | } 63 | } 64 | } 65 | } 66 | // Repeat for other sections with adjusted content 67 | div { 68 | class: "p-4 md:w-1/3", 69 | div { 70 | class: "flex rounded-lg h-full bg-base-200 p-8 flex-col", 71 | div { 72 | class: "flex items-center mb-3", 73 | div { 74 | class: "w-8 h-8 mr-3 inline-flex items-center justify-center rounded-full bg-indigo-500 text-white flex-shrink-0", 75 | svg { 76 | fill: "none", 77 | stroke: "currentColor", 78 | stroke_linecap: "round", 79 | stroke_linejoin: "round", 80 | stroke_width: "2", 81 | class: "w-5 h-5", 82 | view_box: "0 0 24 24", 83 | path { d: "M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" } 84 | circle { cx: "12", cy: "7", r: "4" } 85 | } 86 | } 87 | h2 { 88 | class: "text-lg title-font font-medium", 89 | "{benefit2}" 90 | } 91 | } 92 | div { 93 | class: "flex-grow", 94 | p { 95 | class: "leading-relaxed text-base", 96 | "{benefit2_desc}" 97 | } 98 | } 99 | } 100 | } 101 | div { 102 | class: "p-4 md:w-1/3", 103 | div { 104 | class: "flex rounded-lg h-full bg-base-200 p-8 flex-col", 105 | div { 106 | class: "flex items-center mb-3", 107 | div { 108 | class: "w-8 h-8 mr-3 inline-flex items-center justify-center rounded-full bg-indigo-500 text-white flex-shrink-0", 109 | svg { 110 | fill: "none", 111 | stroke: "currentColor", 112 | stroke_linecap: "round", 113 | stroke_linejoin: "round", 114 | stroke_width: "2", 115 | class: "w-5 h-5", 116 | view_box: "0 0 24 24", 117 | circle { cx: "6", cy: "6", r: "3" } 118 | circle { cx: "6", cy: "18", r: "3" } 119 | path { d: "M20 4L8.12 15.88M14.47 14.48L20 20M8.12 8.12L12 12" } 120 | } 121 | } 122 | h2 { 123 | class: "text-lg title-font font-medium", 124 | "{benefit3}" 125 | } 126 | } 127 | div { 128 | class: "flex-grow", 129 | p { 130 | class: "leading-relaxed text-base", 131 | "{benefit3_desc}" 132 | } 133 | } 134 | } 135 | } 136 | } 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/marketing/customer_logos.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn Customers(class: Option) -> Element { 5 | rsx! { 6 | section { 7 | class: format!("flex flex-col items-center {}", class.unwrap_or("".to_string())), 8 | span { 9 | class: "badge badge-primary badge-outline", 10 | "Trusted by the World's Best Companies" 11 | } 12 | h3 { 13 | class: "mt-4 mb-4", 14 | "Built with support from our partners" 15 | } 16 | div { 17 | class: "flex gap-6 space-between", 18 | svg { 19 | xmlns: "http://www.w3.org/2000/svg", 20 | view_box: "0 0 120 60", 21 | fill: "currentColor", 22 | height: "40", 23 | width: "auto", 24 | path { 25 | d: "M64.87 11.572l1.144.02 3.108-3.108.15-1.317c-2.47-2.197-5.72-3.534-9.277-3.534-6.44 0-11.876 4.382-13.486 10.318.34-.237 1.065-.06 1.065-.06l6.212-1.022s.32-.53.48-.497a7.76 7.76 0 0 1 10.605-.8z" 26 | }, 27 | path { 28 | d: "M73.5 13.962a13.99 13.99 0 0 0-4.216-6.796l-4.402 4.402a7.75 7.75 0 0 1 2.895 6.039v.777c2.142 0 3.88 1.743 3.88 3.88s-1.743 3.88-3.88 3.88h-7.762l-.777.78v4.658l.777.773h7.762A10.11 10.11 0 0 0 77.86 22.265c-.004-3.436-1.736-6.48-4.37-8.303z" 29 | }, 30 | path { 31 | d: "M52.234 32.362h7.76V26.15h-7.76a3.84 3.84 0 0 1-1.597-.347l-1.12.343-3.108 3.108-.272 1.05a9.96 9.96 0 0 0 6.098 2.06z" 32 | }, 33 | path { 34 | d: "M52.234 12.175A10.11 10.11 0 0 0 42.14 22.269a10.08 10.08 0 0 0 4 8.04l4.5-4.5a3.88 3.88 0 0 1-2.288-3.538c0-2.142 1.743-3.88 3.88-3.88a3.89 3.89 0 0 1 3.538 2.288l4.5-4.5c-1.846-2.43-4.76-4-8.04-4z" 35 | }, 36 | path { 37 | d: "M12 51.937c-2.12 0-3.94-.75-5.474-2.25s-2.3-3.304-2.3-5.408.765-3.908 2.3-5.408S9.883 36.62 12 36.62a7.32 7.32 0 0 1 5.249 2.11l-1.477 1.477a5.32 5.32 0 0 0-3.773-1.495c-1.53 0-2.83.54-3.896 1.627a5.41 5.41 0 0 0-1.597 3.941c0 1.546.53 2.857 1.597 3.94a5.25 5.25 0 0 0 3.896 1.627c1.558 0 2.845-.5 3.87-1.534.6-.6 1-1.5 1.14-2.635h-5.006v-2.092h7.044c.075.372.1.8.1 1.3 0 2.056-.603 3.686-1.813 4.895-1.372 1.435-3.15 2.15-5.345 2.15zm16.37-1.4c-.96.94-2.13 1.4-3.512 1.4s-2.554-.47-3.512-1.4-1.438-2.113-1.438-3.52.48-2.58 1.438-3.52 2.13-1.4 3.512-1.4 2.554.47 3.512 1.4 1.438 2.116 1.438 3.52-.48 2.58-1.438 3.52zm-5.474-1.38a2.63 2.63 0 0 0 1.963.849c.76 0 1.414-.282 1.963-.85s.822-1.28.822-2.14c0-.87-.27-1.588-.813-2.15s-1.198-.84-1.972-.84a2.64 2.64 0 0 0-1.972.84c-.543.56-.813 1.276-.813 2.15 0 .858.273 1.573.822 2.14zm16.273 1.38c-.96.94-2.13 1.4-3.512 1.4s-2.554-.47-3.512-1.4-1.438-2.113-1.438-3.52.48-2.58 1.438-3.52 2.13-1.4 3.512-1.4 2.554.47 3.512 1.4 1.438 2.116 1.438 3.52-.48 2.58-1.438 3.52zm-5.474-1.38a2.63 2.63 0 0 0 1.963.849c.76 0 1.414-.282 1.963-.85s.822-1.28.822-2.14c0-.87-.27-1.588-.813-2.15s-1.198-.84-1.972-.84a2.64 2.64 0 0 0-1.972.84c-.543.56-.813 1.276-.813 2.15 0 .858.273 1.573.822 2.14zm12.573 7.22c-1.095 0-2.017-.294-2.764-.88s-1.282-1.264-1.606-2.038l1.888-.783c.198.474.5.885.933 1.234s.94.522 1.552.522c.822 0 1.468-.25 1.933-.747s.7-1.216.7-2.15v-.7h-.075c-.6.747-1.477 1.122-2.596 1.122-1.258 0-2.36-.48-3.307-1.438a4.76 4.76 0 0 1-1.42-3.476 4.82 4.82 0 0 1 1.42-3.503c.945-.963 2.05-1.447 3.307-1.447.56 0 1.068.105 1.522.318s.813.474 1.074.783h.075V42.4h2.056v8.857c0 1.72-.438 3.004-1.318 3.86-.88.85-2.002 1.28-3.373 1.28zm.15-6.372a2.41 2.41 0 0 0 1.879-.849c.504-.567.756-1.273.756-2.122 0-.858-.252-1.576-.756-2.15a2.4 2.4 0 0 0-1.879-.858c-.76 0-1.408.288-1.942.858s-.804 1.288-.804 2.15c0 .846.267 1.555.804 2.122s1.183.85 1.942.85zM54.62 37.14v14.5h-2.167v-14.5zm5.94 14.796c-1.396 0-2.56-.474-3.494-1.42s-1.402-2.116-1.402-3.512c0-1.444.45-2.63 1.354-3.55a4.45 4.45 0 0 1 3.298-1.384c.597 0 1.153.108 1.663.327a3.92 3.92 0 0 1 1.27.84 5.84 5.84 0 0 1 .804.999 6.12 6.12 0 0 1 .486.972l.225.56L58.17 48.5c.5.996 1.3 1.495 2.392 1.495.996 0 1.807-.453 2.428-1.363l1.68 1.122c-.375.56-.903 1.065-1.588 1.513s-1.528.67-2.524.67zm-2.746-5.08l4.4-1.83c-.126-.312-.354-.564-.7-.756a2.26 2.26 0 0 0-1.14-.288c-.636 0-1.23.26-1.783.783s-.82 1.222-.795 2.092zm18.33 5.08c-1.97 0-3.62-.666-4.952-2s-2-2.995-2-4.988.666-3.656 2-4.988 2.983-2 4.952-2c2.017 0 3.656.73 4.913 2.185l-1.195 1.16c-.9-1.134-2.15-1.7-3.72-1.7-1.46 0-2.686.492-3.7 1.477s-1.504 2.272-1.504 3.866.5 2.884 1.504 3.87 2.233 1.477 3.7 1.477c1.606 0 2.977-.648 4.1-1.942l1.195 1.195a6.51 6.51 0 0 1-2.3 1.747 7.02 7.02 0 0 1-3.004.642zm8.556-.296h-1.72V38.263h1.72zm2.803-8.06c.885-.927 2-1.393 3.382-1.393s2.497.465 3.382 1.393 1.327 2.1 1.327 3.485-.44 2.557-1.327 3.485-2 1.393-3.382 1.393-2.497-.465-3.382-1.393-1.327-2.1-1.327-3.485.44-2.557 1.327-3.485zm1.28 5.883c.6.603 1.294.906 2.1.906s1.5-.303 2.1-.906.888-1.405.888-2.4-.297-1.798-.888-2.4-1.294-.906-2.1-.906-1.5.303-2.1.906-.888 1.405-.888 2.4.297 1.798.888 2.4zm16.32 2.177h-1.645v-1.27h-.075c-.26.435-.66.807-1.195 1.1s-1.1.46-1.7.46c-1.147 0-2.014-.348-2.605-1.047s-.888-1.633-.888-2.803v-5.606h1.72v5.324c0 1.708.753 2.56 2.26 2.56a2.1 2.1 0 0 0 1.738-.858 3.13 3.13 0 0 0 .672-1.981v-5.045h1.72v9.157zm5.828.297c-1.183 0-2.206-.468-3.064-1.402s-1.288-2.092-1.288-3.476.43-2.542 1.288-3.476 1.882-1.402 3.064-1.402c.696 0 1.324.15 1.88.447s.97.672 1.243 1.122h.075l-.075-1.27v-4.22h1.72v13.38h-1.645v-1.27h-.075c-.273.447-.687.822-1.243 1.122-.555.294-1.183.444-1.88.444zm.28-1.57a2.74 2.74 0 0 0 2.065-.897c.567-.597.85-1.402.85-2.4s-.282-1.813-.85-2.4a2.74 2.74 0 0 0-2.065-.897c-.798 0-1.483.303-2.056.906s-.858 1.405-.858 2.4.285 1.798.858 2.4a2.73 2.73 0 0 0 2.056.906z" 38 | } 39 | } 40 | svg { 41 | xmlns: "http://www.w3.org/2000/svg", 42 | view_box: "35.188 31.512 351.46 258.785", 43 | fill: "currentColor", 44 | height: "40", 45 | width: "auto", 46 | path { 47 | d: "M384.195 282.109c0 3.771-2.769 6.302-6.047 6.302v-.023c-3.371.023-6.089-2.508-6.089-6.278 0-3.769 2.718-6.293 6.089-6.293 3.279-.001 6.047 2.523 6.047 6.292zm2.453 0c0-5.176-4.02-8.18-8.5-8.18-4.511 0-8.531 3.004-8.531 8.18 0 5.172 4.021 8.188 8.531 8.188 4.48 0 8.5-3.016 8.5-8.188m-9.91.692h.91l2.109 3.703h2.315l-2.336-3.859c1.207-.086 2.2-.66 2.2-2.285 0-2.02-1.393-2.668-3.75-2.668h-3.411v8.812h1.961l.002-3.703m0-1.492v-2.121h1.364c.742 0 1.753.06 1.753.965 0 .984-.523 1.156-1.398 1.156h-1.719M329.406 237.027l10.598 28.992H318.48l10.926-28.992zm-11.35-11.289l-24.423 61.88h17.245l3.863-10.935h28.903l3.656 10.935h18.722l-24.605-61.888-23.361.008zm-49.033 61.903h17.497v-61.922l-17.5-.004.003 61.926zm-121.467-61.926l-14.598 49.078-13.984-49.074-18.879-.004 19.972 61.926h25.207l20.133-61.926h-17.851zm70.725 13.484h7.521c10.909 0 17.966 4.898 17.966 17.609 0 12.713-7.057 17.612-17.966 17.612h-7.521v-35.221zm-17.35-13.484v61.926h28.365c15.113 0 20.049-2.512 25.385-8.147 3.769-3.957 6.207-12.642 6.207-22.134 0-8.707-2.063-16.469-5.66-21.305-6.48-8.648-15.816-10.34-29.75-10.34h-24.547zm-165.743-.086v62.012h17.645v-47.086l13.672.004c4.527 0 7.754 1.129 9.934 3.457 2.765 2.945 3.894 7.699 3.894 16.396v27.229h17.098v-34.262c0-24.453-15.586-27.75-30.836-27.75H35.188zm137.583.086l.007 61.926h17.489v-61.926h-17.496z" 48 | }, 49 | path { 50 | d: "M82.211 102.414s22.504-33.203 67.437-36.638V53.73c-49.769 3.997-92.867 46.149-92.867 46.149s24.41 70.564 92.867 77.026v-12.804c-50.237-6.32-67.437-61.687-67.437-61.687zm67.437 36.223v11.727c-37.968-6.77-48.507-46.237-48.507-46.237s18.23-20.195 48.507-23.47v12.867c-.023 0-.039-.007-.058-.007-15.891-1.907-28.305 12.938-28.305 12.938s6.958 24.99 28.363 32.182m0-107.125V53.73c1.461-.112 2.922-.207 4.391-.257 56.582-1.907 93.449 46.406 93.449 46.406s-42.343 51.488-86.457 51.488c-4.043 0-7.828-.375-11.383-1.005v13.739a75.04 75.04 0 0 0 9.481.612c41.051 0 70.738-20.965 99.484-45.778 4.766 3.817 24.278 13.103 28.289 17.167-27.332 22.884-91.031 41.33-127.144 41.33-3.481 0-6.824-.211-10.11-.528v19.306H305.68V31.512H149.648zm0 49.144V65.777c1.446-.101 2.903-.179 4.391-.226 40.688-1.278 67.382 34.965 67.382 34.965s-28.832 40.042-59.746 40.042c-4.449 0-8.438-.715-12.028-1.922V93.523c15.84 1.914 19.028 8.911 28.551 24.786l21.181-17.859s-15.461-20.277-41.524-20.277c-2.834-.001-5.545.198-8.207.483" 51 | } 52 | } 53 | svg { 54 | xmlns: "http://www.w3.org/2000/svg", 55 | view_box: "123.5 281.88608274 778.8 460.11391726", 56 | fill: "currentColor", 57 | height: "40", 58 | width: "auto", 59 | path { 60 | d: "m344.4 449.1c0 9.4 1.1 17.1 2.8 22.7a141 141 0 0 0 8.2 18.5 10.6 10.6 0 0 1 1.8 5.8c0 2.6-1.5 5.2-4.9 7.7l-16 10.8a12.5 12.5 0 0 1 -6.7 2.3c-2.5 0-5.1-1.3-7.6-3.6a81.7 81.7 0 0 1 -9.2-12c-2.6-4.4-5.2-9.3-8-15.1q-29.9 35.3-75.1 35.3c-21.4 0-38.5-6.2-51-18.5s-18.9-28.6-18.9-49.1 7.6-39.4 23.2-52.7 36.3-19.9 62.6-19.9a199 199 0 0 1 27.1 2c9.4 1.3 19.1 3.3 29.3 5.6v-18.6c0-19.5-4.1-33-12-41s-21.9-11.7-41.6-11.7a116.2 116.2 0 0 0 -27.6 3.3 205.5 205.5 0 0 0 -27.6 8.7 68.7 68.7 0 0 1 -8.9 3.3 16.9 16.9 0 0 1 -4.1.8c-3.6 0-5.4-2.6-5.4-8v-12.5c0-4.1.5-7.2 1.8-8.9s3.6-3.6 7.2-5.4a142.4 142.4 0 0 1 32.1-11.5 152 152 0 0 1 39.9-4.9c30.4 0 52.6 6.9 66.9 20.7s21.2 34.8 21.2 63v82.9zm-103.7 38.9a81.7 81.7 0 0 0 26.3-4.7c9.2-3 17.4-8.7 24.3-16.3a40.7 40.7 0 0 0 8.7-16.4 94 94 0 0 0 2.5-22.3v-10.7a228.2 228.2 0 0 0 -23.5-4.4 195.7 195.7 0 0 0 -24-1.5c-17.1 0-29.6 3.3-38 10.2s-12.5 16.7-12.5 29.5 3 20.9 9.4 27.1 15.1 9.5 26.8 9.5zm205.1 27.6c-4.6 0-7.6-.8-9.7-2.6s-3.8-5.1-5.3-10l-60.1-197.7c-1.5-5.1-2.3-8.5-2.3-10.3 0-4 2.1-6.3 6.2-6.3h25c4.9 0 8.2.7 10 2.5s3.5 5.1 5.1 10l42.9 169.4 39.8-169.4c1.3-5.1 2.8-8.5 4.9-10s5.6-2.5 10.2-2.5h20.4c4.9 0 8.2.7 10.3 2.5s3.8 5.1 4.8 10l40.4 171.4 44.2-171.4c1.5-5.1 3.3-8.5 5.1-10s5.3-2.5 9.9-2.5h23.8c4.1 0 6.4 2 6.4 6.3a32.6 32.6 0 0 1 -.5 4.1 41.3 41.3 0 0 1 -1.8 6.4l-61.6 197.8c-1.5 5.1-3.3 8.4-5.4 10s-5.3 2.5-9.7 2.5h-21.9c-4.9 0-8.2-.7-10.2-2.5s-3.9-5.1-4.9-10.3l-39.6-165-39.3 164.8c-1.3 5.1-2.8 8.4-4.9 10.2s-5.6 2.6-10.2 2.6zm328.3 6.9a167.8 167.8 0 0 1 -39.4-4.6c-12.7-3.1-22.7-6.4-29.3-10.2-4.1-2.4-6.9-4.9-8-7.2a18.6 18.6 0 0 1 -1.5-7.2v-13c0-5.4 2-8 5.9-8a15.4 15.4 0 0 1 4.6.8c1.5.5 3.8 1.5 6.4 2.6a135.8 135.8 0 0 0 28.1 8.9 148.7 148.7 0 0 0 30.4 3.1c16 0 28.6-2.8 37.2-8.4s13.3-13.9 13.3-24.4a25.1 25.1 0 0 0 -6.9-17.9c-4.6-4.8-13.3-9.2-25.8-13.3l-37-11.5c-18.7-5.9-32.4-14.6-40.9-26.1a61 61 0 0 1 -12.7-37.1c0-10.7 2.3-20.2 6.9-28.4a64.3 64.3 0 0 1 18.3-20.9 82.2 82.2 0 0 1 26.6-13.4 113.8 113.8 0 0 1 32.2-4.3 140.1 140.1 0 0 1 17.1 1c5.9.8 11.2 1.8 16.6 2.8s10 2.6 14.6 4.1a64 64 0 0 1 10.7 4.6c3.6 2.1 6.1 4.1 7.7 6.4a14.3 14.3 0 0 1 2.3 8.5v12c0 5.4-2.1 8.2-5.9 8.2-2.1 0-5.4-1-9.7-3.1-14.6-6.6-30.9-10-49.1-10-14.5 0-26 2.3-33.9 7.2s-12 12.3-12 22.8a24 24 0 0 0 7.6 18.1c5.1 4.9 14.6 9.8 28.1 14.1l36.3 11.5c18.4 5.9 31.7 14.1 39.6 24.6a58 58 0 0 1 11.7 35.8 66.5 66.5 0 0 1 -6.6 29.7 68.5 68.5 0 0 1 -18.7 22.5c-7.9 6.4-17.3 11-28.3 14.3a120.7 120.7 0 0 1 -36.5 5.4z" 61 | }, 62 | path { 63 | d: "m822.3 646.8c-84 62.2-206.1 95.2-311.1 95.2-147.1 0-279.7-54.5-379.8-145.1-7.9-7.1-.8-16.8 8.7-11.2 108.3 62.9 241.9 101 380.1 101 93.2 0 195.6-19.4 289.9-59.3 14-6.4 26 9.2 12.2 19.4zm35-39.9c-10.7-13.8-71-6.6-98.3-3.3-8.2 1-9.5-6.1-2.1-11.5 48.1-33.8 127-24.1 136.2-12.8s-2.6 90.6-47.5 128.4c-6.9 5.9-13.6 2.8-10.5-4.8 10.2-25.4 33-82.4 22.2-96z" 64 | } 65 | } 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/marketing/extra_footer.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn ExtraFooter(title: String, image: String, cta: String, cta_url: String) -> Element { 5 | rsx! { 6 | section { 7 | class: "mt-12 flex flex-col items-center text-center p-4 bg-secondary-content", 8 | h2 { 9 | class: "mt-4 mb-4 max-w-lg text-2xl font-bold", 10 | "{title}" 11 | } 12 | img { 13 | class: "lg:max-w-md", 14 | alt: "Product Screenshot", 15 | src: "{image}" 16 | } 17 | div { 18 | class: "mt-4 flex flex-col space-y-4 sm:flex-row sm:space-y-0 sm:space-x-4", 19 | a { 20 | href: "{cta_url}", 21 | class: "btn btn-primary", 22 | "{cta}" 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/marketing/faq_accordian.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[derive(Clone, PartialEq)] 4 | pub struct FaqText { 5 | pub question: String, 6 | pub answer: String, 7 | } 8 | 9 | #[component] 10 | pub fn Faq(questions: Vec, class: Option) -> Element { 11 | let class = class.unwrap_or("".to_string()); 12 | rsx! { 13 | section { 14 | class: format!("{class} lg:max-w-5xl"), 15 | h1 { 16 | class: "text-3xl font-medium text-primary title-font mb-12 text-center", 17 | "Frequently asked questions" 18 | } 19 | for question in questions { 20 | div { 21 | class: "collapse collapse-arrow bg-base-200", 22 | input { 23 | r#type: "radio", 24 | name: "faq-accordion" 25 | } 26 | div { 27 | class: "collapse-title text-xl font-medium", 28 | "{question.question}" 29 | } 30 | div { 31 | class: "collapse-content", 32 | p { "{question.answer}" } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/marketing/features.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn GraphSvg() -> Element { 5 | rsx! { 6 | svg { 7 | fill: "currentColor", 8 | width: "50", 9 | height: "50", 10 | view_box: "0 0 20 20", 11 | xmlns: "http://www.w3.org/2000/svg", 12 | path { 13 | fill_rule: "evenodd", 14 | d: "M3 3a1 1 0 000 2v8a2 2 0 002 2h2.586l-1.293 1.293a1 1 0 101.414 1.414L10 15 | 15.414l2.293 2.293a1 1 0 001.414-1.414L12.414 15H15a2 2 0 002-2V5a1 1 0 16 | 100-2H3zm11.707 4.707a1 1 0 00-1.414-1.414L10 9.586 8.707 8.293a1 1 0 17 | 00-1.414 0l-2 2a1 1 0 101.414 1.414L8 10.414l1.293 1.293a1 1 0 001.414 0l4-4z", 18 | clip_rule: "evenodd", 19 | } 20 | } 21 | } 22 | } 23 | 24 | #[derive(Clone, PartialEq)] 25 | pub struct Feature { 26 | pub title: String, 27 | pub description: String, 28 | } 29 | 30 | #[component] 31 | pub fn Features( 32 | features: Vec, 33 | title: String, 34 | description: String, 35 | class: Option, 36 | ) -> Element { 37 | let class = class.unwrap_or("".to_string()); 38 | rsx! { 39 | section { 40 | class: format!("{class} body-font"), 41 | div { 42 | class: "mx-auto", 43 | div { 44 | class: "mb-8 lg:mb-16", 45 | h2 { 46 | class: "mb-4 text-4xl tracking-tight text-primary", 47 | "{title}" 48 | } 49 | p { 50 | class: "text-gray-500 sm:text-xl dark:text-gray-400", 51 | "{description}" 52 | } 53 | } 54 | div { 55 | class: "space-y-8 md:grid md:grid-cols-2 lg:grid-cols-3 md:gap-12 md:space-y-0", 56 | for feature in features { 57 | div { 58 | div { 59 | class: "mb-4 w-10 h-10 lg:h-12 lg:w-12", 60 | GraphSvg {} 61 | } 62 | h3 { 63 | class: "mb-2 text-primary text-xl font-bold", 64 | "{feature.title}" 65 | } 66 | p { 67 | "{feature.description}" 68 | } 69 | } 70 | } 71 | } 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/marketing/hero.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn Hero(title: String, subtitle: String, 5 | cta: String, 6 | cta_link: String,) -> Element { 7 | rsx! { 8 | section { 9 | div { 10 | class: "flex justify-center text-center", 11 | div { 12 | class: "max-w-lg", 13 | h1 { 14 | class: "text-5xl font-bold", 15 | "{title}" 16 | } 17 | p { 18 | class: "py-6", 19 | "{subtitle}" 20 | } 21 | div { 22 | class: "flex gap-2 justify-center", 23 | a { 24 | class: "btn btn-primary", 25 | href: cta_link, 26 | "{cta}" 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/marketing/image_feature.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn ImageFeature( 5 | title: String, 6 | sub_title: String, 7 | text: String, 8 | title1: String, 9 | text1: String, 10 | title2: String, 11 | text2: String, 12 | title3: String, 13 | text3: String, 14 | image: String, 15 | ) -> Element { 16 | rsx! { 17 | section { class: "lg:max-w-5xl overflow-hidden py-24 sm:py-32", 18 | div { class: "mx-auto max-w-7xl px-6 lg:px-8", 19 | div { class: "mx-auto grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 sm:gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-2", 20 | div { class: "lg:pr-8 lg:pt-4", 21 | div { class: "lg:max-w-lg", 22 | h2 { 23 | class: "badge badge-outline", 24 | "{title}" 25 | } 26 | p { 27 | class: "mt-2 text-3xl font-bold tracking-tight sm:text-4xl text-primary", 28 | "{sub_title}" 29 | } 30 | p { 31 | class: "mt-6 text-lg leading-8", 32 | "{text}" 33 | } 34 | dl { class: "mt-10 max-w-xl space-y-8 text-base leading-7 lg:max-w-none", 35 | div { class: "relative pl-9", 36 | dt { class: "inline font-semibold", 37 | svg { 38 | "fill": "currentColor", 39 | "aria-hidden": "true", 40 | "viewBox": "0 0 20 20", 41 | class: "absolute left-1 top-1 h-5 w-5", 42 | path { 43 | "fill-rule": "evenodd", 44 | "clip-rule": "evenodd", 45 | "d": "M5.5 17a4.5 4.5 0 01-1.44-8.765 4.5 4.5 0 018.302-3.046 3.5 3.5 0 014.504 4.272A4 4 0 0115 17H5.5zm3.75-2.75a.75.75 0 001.5 0V9.66l1.95 2.1a.75.75 0 101.1-1.02l-3.25-3.5a.75.75 0 00-1.1 0l-3.25 3.5a.75.75 0 101.1 1.02l1.95-2.1v4.59z" 46 | } 47 | } 48 | "{title1}" 49 | } 50 | dd { class: "inline", "{text1}" } 51 | } 52 | div { class: "relative pl-9", 53 | dt { class: "inline font-semibold", 54 | svg { 55 | "aria-hidden": "true", 56 | "viewBox": "0 0 20 20", 57 | "fill": "currentColor", 58 | class: "absolute left-1 top-1 h-5 w-5", 59 | path { 60 | "clip-rule": "evenodd", 61 | "fill-rule": "evenodd", 62 | "d": "M10 1a4.5 4.5 0 00-4.5 4.5V9H5a2 2 0 00-2 2v6a2 2 0 002 2h10a2 2 0 002-2v-6a2 2 0 00-2-2h-.5V5.5A4.5 4.5 0 0010 1zm3 8V5.5a3 3 0 10-6 0V9h6z" 63 | } 64 | } 65 | "{title2}" 66 | } 67 | dd { class: "inline", "{text2}" } 68 | } 69 | div { class: "relative pl-9", 70 | dt { class: "inline font-semibold", 71 | svg { 72 | "aria-hidden": "true", 73 | "fill": "currentColor", 74 | "viewBox": "0 0 20 20", 75 | class: "absolute left-1 top-1 h-5 w-5", 76 | path { "d": "M4.632 3.533A2 2 0 016.577 2h6.846a2 2 0 011.945 1.533l1.976 8.234A3.489 3.489 0 0016 11.5H4c-.476 0-.93.095-1.344.267l1.976-8.234z" } 77 | path { 78 | "fill-rule": "evenodd", 79 | "d": "M4 13a2 2 0 100 4h12a2 2 0 100-4H4zm11.24 2a.75.75 0 01.75-.75H16a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75h-.01a.75.75 0 01-.75-.75V15zm-2.25-.75a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75H13a.75.75 0 00.75-.75V15a.75.75 0 00-.75-.75h-.01z", 80 | "clip-rule": "evenodd" 81 | } 82 | } 83 | "{title3}" 84 | } 85 | dd { class: "inline", "{text3}" } 86 | } 87 | } 88 | } 89 | } 90 | img { 91 | height: "1442", 92 | src: "{image}", 93 | alt: "Product screenshot", 94 | width: "2432", 95 | class: "w-[48rem] max-w-none rounded-xl shadow-xl ring-1 ring-gray-400/10 sm:w-[57rem] md:-ml-4 lg:-ml-0" 96 | } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/marketing/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod benefits; 2 | pub mod customer_logos; 3 | pub mod extra_footer; 4 | pub mod faq_accordian; 5 | pub mod features; 6 | pub mod hero; 7 | pub mod image_feature; 8 | pub mod problem_solution; 9 | pub mod quad_feature; 10 | pub mod security; 11 | pub mod small_image_feature; 12 | pub mod team; 13 | pub mod testamonials; 14 | pub mod video_hero; 15 | pub mod webinar; 16 | -------------------------------------------------------------------------------- /src/marketing/problem_solution.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn ProblemSolution( 5 | image: String, 6 | title: String, 7 | problem: String, 8 | solution: String, 9 | class: Option, 10 | ) -> Element { 11 | rsx! { 12 | section { 13 | class: format!("md:flex lg:max-w-5xl gap-8 w-full {}", class.unwrap_or("".to_string())), 14 | div { 15 | class: "flex-1", 16 | h1 { 17 | class: "text-primary sm:text-3xl text-2xl font-medium", 18 | "{title}" 19 | } 20 | p { 21 | class: "py-6", 22 | "{problem}" 23 | } 24 | p { 25 | class: "py-6", 26 | "{solution}" 27 | } 28 | } 29 | div { 30 | class: "flex-1", 31 | img { 32 | width: "560", 33 | height: "315", 34 | loading: "lazy", 35 | class: "w-full aspect-[4/3]", 36 | alt: "Product screenshot", 37 | src: "{image}", 38 | } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/marketing/quad_feature.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn QuadFeature( 5 | title: String, 6 | sub_title: String, 7 | text: String, 8 | title1: String, 9 | text1: String, 10 | title2: String, 11 | text2: String, 12 | title3: String, 13 | text3: String, 14 | title4: String, 15 | text4: String, 16 | ) -> Element { 17 | rsx! { 18 | section { class: "lg:max-w-5xl py-24 sm:py-32", 19 | div { class: "mx-auto max-w-7xl px-6 lg:px-8", 20 | div { class: "mx-auto max-w-2xl lg:text-center", 21 | h2 { class: "badge badge-outline", "{title}" } 22 | p { class: "mt-2 text-3xl font-bold tracking-tight sm:text-4xl text-primary", 23 | "{sub_title}" 24 | } 25 | p { class: "mt-6 text-lg leading-8", "{text}" } 26 | } 27 | div { class: "mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-24 lg:max-w-4xl", 28 | dl { class: "grid max-w-xl grid-cols-1 gap-x-8 gap-y-10 lg:max-w-none lg:grid-cols-2 lg:gap-y-16", 29 | div { class: "relative pl-16", 30 | dt { class: "text-base font-semibold leading-7", 31 | div { class: "absolute left-0 top-0 flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-600", 32 | svg { 33 | "viewBox": "0 0 24 24", 34 | "stroke": "currentColor", 35 | "aria-hidden": "true", 36 | "stroke-width": "1.5", 37 | "fill": "none", 38 | class: "h-6 w-6 text-white", 39 | path { 40 | "stroke-linejoin": "round", 41 | "d": "M12 16.5V9.75m0 0l3 3m-3-3l-3 3M6.75 19.5a4.5 4.5 0 01-1.41-8.775 5.25 5.25 0 0110.233-2.33 3 3 0 013.758 3.848A3.752 3.752 0 0118 19.5H6.75z", 42 | "stroke-linecap": "round" 43 | } 44 | } 45 | } 46 | "{title1}" 47 | } 48 | dd { class: "mt-2 text-base leading-7", "{text1}" } 49 | } 50 | div { class: "relative pl-16", 51 | dt { class: "text-base font-semibold leading-7", 52 | div { class: "absolute left-0 top-0 flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-600", 53 | svg { 54 | "fill": "none", 55 | "aria-hidden": "true", 56 | "stroke": "currentColor", 57 | "viewBox": "0 0 24 24", 58 | "stroke-width": "1.5", 59 | class: "h-6 w-6 text-white", 60 | path { 61 | "d": "M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z", 62 | "stroke-linejoin": "round", 63 | "stroke-linecap": "round" 64 | } 65 | } 66 | } 67 | "{title2}" 68 | } 69 | dd { class: "mt-2 text-base leading-7", "{text2}" } 70 | } 71 | div { class: "relative pl-16", 72 | dt { class: "text-base font-semibold leading-7", 73 | div { class: "absolute left-0 top-0 flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-600", 74 | svg { 75 | "aria-hidden": "true", 76 | "stroke": "currentColor", 77 | "stroke-width": "1.5", 78 | "viewBox": "0 0 24 24", 79 | "fill": "none", 80 | class: "h-6 w-6 text-white", 81 | path { 82 | "stroke-linejoin": "round", 83 | "d": "M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99", 84 | "stroke-linecap": "round" 85 | } 86 | } 87 | } 88 | "{title3}" 89 | } 90 | dd { class: "mt-2 text-base leading-7", "{text3}" } 91 | } 92 | div { class: "relative pl-16", 93 | dt { class: "text-base font-semibold leading-7", 94 | div { class: "absolute left-0 top-0 flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-600", 95 | svg { 96 | "aria-hidden": "true", 97 | "fill": "none", 98 | "viewBox": "0 0 24 24", 99 | "stroke-width": "1.5", 100 | "stroke": "currentColor", 101 | class: "h-6 w-6 text-white", 102 | path { 103 | "stroke-linecap": "round", 104 | "d": "M7.864 4.243A7.5 7.5 0 0119.5 10.5c0 2.92-.556 5.709-1.568 8.268M5.742 6.364A7.465 7.465 0 004.5 10.5a7.464 7.464 0 01-1.15 3.993m1.989 3.559A11.209 11.209 0 008.25 10.5a3.75 3.75 0 117.5 0c0 .527-.021 1.049-.064 1.565M12 10.5a14.94 14.94 0 01-3.6 9.75m6.633-4.596a18.666 18.666 0 01-2.485 5.33", 105 | "stroke-linejoin": "round" 106 | } 107 | } 108 | } 109 | "{title4}" 110 | } 111 | dd { class: "mt-2 text-base leading-7", "{text4}" } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/marketing/security.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn Shield(text: String) -> Element { 5 | rsx! { 6 | svg { 7 | view_box: "0 0 16 16", 8 | fill: "currentColor", 9 | stroke: "currentColor", 10 | xmlns: "http://www.w3.org/2000/svg", 11 | width: "60", 12 | height: "60", 13 | g { 14 | id: "SVGRepo_bgCarrier", 15 | stroke_width: "0" 16 | } 17 | g { 18 | id: "SVGRepo_tracerCarrier", 19 | stroke_linecap: "round", 20 | stroke_linejoin: "round" 21 | } 22 | g { 23 | id: "SVGRepo_iconCarrier", 24 | path { 25 | fill_rule: "evenodd", 26 | clip_rule: "evenodd", 27 | d: "M8 16L4.35009 13.3929C2.24773 11.8912 1 9.46667 1 28 | 6.88306V3L8 0L15 3V6.88306C15 9.46667 13.7523 11.8912 29 | 11.6499 13.3929L8 16ZM12.2071 5.70711L10.7929 4.29289L7 30 | 8.08579L5.20711 6.29289L3.79289 7.70711L7 10.9142L12.2071 31 | 5.70711Z", 32 | fill: "currentColor" 33 | } 34 | } 35 | } 36 | h3 { 37 | class: "mt-4", 38 | "{text}" 39 | } 40 | } 41 | } 42 | 43 | #[component] 44 | pub fn Security(class: Option) -> Element { 45 | let class = class.unwrap_or("".to_string()); 46 | rsx! { 47 | section { 48 | class: format!("{class} md:flex flex-row gap-8"), 49 | div { 50 | class: "flex-1", 51 | h2 { 52 | class: "text-3xl tracking-tight text-primary mb-4", 53 | "Built with Enterprise Security, Privacy, and Compliance at Its Core" 54 | } 55 | p { 56 | class: "mb-4", 57 | "Bionic-GPT was built with enterprise security, privacy, and compliance in mind from day one." 58 | } 59 | p { 60 | "Choose Between On Premise or Private Cloud Deployment and keep your data 100% safe." 61 | } 62 | } 63 | div { 64 | class: "mt-12 md:mt-0 flex-1 grid grid-cols-2 gap-8", 65 | div { 66 | class: "text-center block mx-auto", 67 | Shield { 68 | text: "ISO 27001" 69 | } 70 | } 71 | div { 72 | class: "text-center block mx-auto", 73 | Shield { 74 | text: "SOC II" 75 | } 76 | } 77 | div { 78 | class: "text-center block mx-auto", 79 | Shield { 80 | text: "GDPR" 81 | } 82 | } 83 | div { 84 | class: "text-center block mx-auto", 85 | Shield { 86 | text: "Compliance" 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/marketing/small_image_feature.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn SmallImageFeature( 5 | title: String, 6 | sub_title: String, 7 | text: String, 8 | image: String, 9 | flip: bool, 10 | class: Option, 11 | ) -> Element { 12 | let flip = if flip { "flex-row-reverse" } else { "flex-row" }; 13 | let class = class.unwrap_or("".to_string()); 14 | rsx! { 15 | section { 16 | class: "{class} lg:max-w-5xl md:flex {flip} gap-8", 17 | div { 18 | class: "flex-1", 19 | h2 { 20 | class: "badge badge-outline", 21 | "{title}" } 22 | p { 23 | class: "mt-8 text-3xl tracking-tight sm:text-4xl text-primary", 24 | "{sub_title}" 25 | } 26 | p { 27 | class: "mt-6 text-lg leading-8", 28 | "{text}" 29 | } 30 | } 31 | div { 32 | class: "flex-1", 33 | img { 34 | loading: "lazy", 35 | width: "728", 36 | height: "610", 37 | alt: "Product screenshot", 38 | src: "{image}", 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/marketing/team.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn ContactCard(img: String, name: String, role: String) -> Element { 5 | rsx! { 6 | div { 7 | class: "p-2 lg:w-1/3 md:w-1/2 w-full", 8 | div { 9 | class: "h-full flex items-center border-gray-200 border p-4 rounded-lg", 10 | img { 11 | alt: "team", 12 | class: "w-16 h-16 bg-gray-100 object-cover object-center flex-shrink-0 rounded-full mr-4", 13 | src: "{img}", 14 | } 15 | div { 16 | class: "flex-grow", 17 | h2 { 18 | class: "font-medium", 19 | "{name}" 20 | } 21 | p { 22 | class: "text-gray-500", 23 | "{role}" 24 | } 25 | } 26 | } 27 | } 28 | } 29 | } 30 | 31 | #[component] 32 | pub fn Team() -> Element { 33 | rsx! { 34 | section { 35 | class: "lg:max-w-5xl mx-auto", 36 | div { 37 | class: "container py-24 mx-auto", 38 | div { 39 | class: "flex flex-col text-center w-full mb-20", 40 | h1 { 41 | class: "sm:text-3xl text-2xl font-medium mb-4", 42 | "Our Team" 43 | } 44 | p { 45 | class: "lg:w-2/3 mx-auto leading-relaxed", 46 | img { 47 | src: "/contact-us/ian-and-dio.jpeg" 48 | } 49 | } 50 | } 51 | div { 52 | class: "flex flex-wrap -m-2",ContactCard { 53 | name: "Dio".to_string(), 54 | role: "CEO".to_string(), 55 | img: "/contact-us/dio.png".to_string() 56 | } 57 | ContactCard { 58 | name: "Ian".to_string(), 59 | role: "CTO".to_string(), 60 | img: "/contact-us/ian.png".to_string() 61 | } 62 | ContactCard { 63 | name: "Affifa R".to_string(), 64 | role: "UI/UX Designer".to_string(), 65 | img: "/contact-us/affifa-r.png".to_string() 66 | } 67 | ContactCard { 68 | name: "John D".to_string(), 69 | role: "Head of Engineering".to_string(), 70 | img: "/contact-us/john-d.png".to_string() 71 | } 72 | ContactCard { 73 | name: "Ashar P".to_string(), 74 | role: "Growth Engineer".to_string(), 75 | img: "/contact-us/ashar-p.jpeg".to_string() 76 | } 77 | ContactCard { 78 | name: "Diana D".to_string(), 79 | role: "AI Researcher".to_string(), 80 | img: "/contact-us/diane-d.jpeg".to_string() 81 | } 82 | ContactCard { 83 | name: "Nattaliia T".to_string(), 84 | role: "QA Engineer".to_string(), 85 | img: "/contact-us/nattaliia-t.jpeg".to_string() 86 | } 87 | ContactCard { 88 | name: "Anastasia P".to_string(), 89 | role: "Sales & Marketing".to_string(), 90 | img: "/contact-us/anastasia-p.jpeg".to_string() 91 | } 92 | ContactCard { 93 | name: "Martin M".to_string(), 94 | role: "Product Manager".to_string(), 95 | img: "/contact-us/martin-m.jpeg".to_string() 96 | } 97 | 98 | } 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/marketing/testamonials.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn Testamonial(text: String, job: String, person: String, img: String) -> Element { 5 | rsx! { 6 | div { 7 | class: "h-full bg-base-200 p-8 rounded", 8 | svg { 9 | xmlns: "http://www.w3.org/2000/svg", 10 | fill: "currentColor", 11 | class: "block w-5 h-5 text-gray-400 mb-4", 12 | view_box: "0 0 975.036 975.036", 13 | path { 14 | d: "M925.036 57.197h-304c-27.6 0-50 22.4-50 50v304c0 27.601 22.4 50 50 50h145.5c-1.9 79.601-20.4 143.3-55.4 191.2-27.6 37.8-69.399 69.1-125.3 93.8-25.7 11.3-36.8 41.7-24.8 67.101l36 76c11.6 24.399 40.3 35.1 65.1 24.399 66.2-28.6 122.101-64.8 167.7-108.8 55.601-53.7 93.7-114.3 114.3-181.9 20.601-67.6 30.9-159.8 30.9-276.8v-239c0-27.599-22.401-50-50-50zM106.036 913.497c65.4-28.5 121-64.699 166.9-108.6 56.1-53.7 94.4-114.1 115-181.2 20.6-67.1 30.899-159.6 30.899-277.5v-239c0-27.6-22.399-50-50-50h-304c-27.6 0-50 22.4-50 50v304c0 27.601 22.4 50 50 50h145.5c-1.9 79.601-20.4 143.3-55.4 191.2-27.6 37.8-69.4 69.1-125.3 93.8-25.7 11.3-36.8 41.7-24.8 67.101l35.9 75.8c11.601 24.399 40.501 35.2 65.301 24.399z" 15 | } 16 | } 17 | p { 18 | class: "leading-relaxed mb-6", 19 | "{text}" 20 | } 21 | a { 22 | class: "inline-flex items-center", 23 | img { 24 | alt: "testimonial", 25 | src: img, 26 | class: "w-12 h-12 rounded-full flex-shrink-0 object-cover object-center", 27 | } 28 | span { 29 | class: "flex-grow flex flex-col pl-4", 30 | span { 31 | class: "title-font font-medium text-gray-900", 32 | "{person}" 33 | } 34 | span { 35 | class: "text-gray-500 text-sm", 36 | "{job}" 37 | } 38 | } 39 | } 40 | } 41 | } 42 | } 43 | 44 | #[component] 45 | pub fn Testamonials( 46 | text1: String, 47 | job1: String, 48 | person1: String, 49 | img1: String, 50 | text2: String, 51 | job2: String, 52 | person2: String, 53 | img2: String, 54 | class: Option, 55 | ) -> Element { 56 | let class = class.unwrap_or("".to_string()); 57 | rsx! { 58 | section { 59 | class: format!("mx-auto lg:max-w-5xl {class}"), 60 | div { 61 | class: "container mx-auto", 62 | h1 { 63 | class: "text-3xl font-medium text-primary title-font mb-12 text-center", 64 | "Testimonials" 65 | } 66 | div { 67 | class: "md:flex gap-8", 68 | div { 69 | class: "md:w-1/2 w-full", 70 | Testamonial { 71 | person: person1, 72 | text: text1, 73 | job: job1, 74 | img: img1 75 | } 76 | } 77 | div { 78 | class: "mt-5 md:md-0 md:w-1/2 w-full", 79 | Testamonial { 80 | person: person2, 81 | text: text2, 82 | job: job2, 83 | img: img2 84 | } 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/marketing/video_hero.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn VideoHero( 5 | title: String, 6 | subtitle: String, 7 | video: String, 8 | claim: String, 9 | cta: String, 10 | cta_link: String, 11 | ) -> Element { 12 | rsx! { 13 | section { 14 | class: "md:flex flex-row gap-8 text-center md:text-left", 15 | div { 16 | class: "flex-1", 17 | div { 18 | h1 { 19 | class: "text-primary text-2xl md:text-5xl font-bold", 20 | "{title}" 21 | } 22 | p { 23 | class: "py-6", 24 | "{subtitle}" 25 | } 26 | div { 27 | a { 28 | class: "btn btn-primary", 29 | href: cta_link, 30 | "{cta}" 31 | } 32 | strong { 33 | class: "hidden md:inline ml-4", 34 | "{claim}" 35 | } 36 | } 37 | } 38 | } 39 | div { 40 | class: "flex-1 mt-8 md:mt-0", 41 | iframe { 42 | class: "w-full aspect-[16/9]", 43 | src: "{video}", 44 | title: "YouTube video player", 45 | "frameborder": "0", 46 | allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share", 47 | referrerpolicy: "strict-origin-when-cross-origin", 48 | allowfullscreen: true, 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/marketing/webinar.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use dioxus::prelude::*; 4 | 5 | pub fn WebinarHeader() -> Element { 6 | rsx! { 7 | div { 8 | class: "bg-gradient-to-r from-blue-500 to-purple-600 text-white py-2 px-2 text-center whitespace-nowrap", 9 | h1 { 10 | class: "text-md font-bold inline text-white", 11 | "Join our No Code Enterprise RAG webinar" 12 | } 13 | a { 14 | class: "inline-block bg-white text-blue-500 font-semibold py-1 px-3 rounded-full shadow-md hover:bg-gray-100 transition duration-300 ml-4", 15 | href: "https://www.linkedin.com/events/7249357198881886208/comments/", 16 | "Reserve Your Spot" 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/modal.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use dioxus::prelude::*; 4 | 5 | #[derive(Props, Clone, PartialEq)] 6 | pub struct ModalProps { 7 | trigger_id: String, 8 | children: Element, 9 | submit_action: Option, 10 | class: Option, 11 | } 12 | 13 | #[component] 14 | pub fn Modal(props: ModalProps) -> Element { 15 | let class = if let Some(class) = props.class { 16 | format!("modal {}", class) 17 | } else { 18 | "modal".to_string() 19 | }; 20 | rsx!( 21 | if let Some(action) = &props.submit_action { 22 | form { 23 | action: "{action}", 24 | method: "post", 25 | dialog { 26 | class: "{class}", 27 | id: "{props.trigger_id}", 28 | {props.children} 29 | } 30 | } 31 | } else { 32 | dialog { 33 | class: "{class}", 34 | id: "{props.trigger_id}", 35 | {props.children} 36 | } 37 | } 38 | ) 39 | } 40 | 41 | #[derive(Props, Clone, PartialEq)] 42 | pub struct ModalBodyProps { 43 | children: Element, 44 | class: Option, 45 | } 46 | 47 | #[component] 48 | pub fn ModalBody(props: ModalBodyProps) -> Element { 49 | let class = if let Some(class) = props.class { 50 | class 51 | } else { 52 | "".to_string() 53 | }; 54 | 55 | let class = format!("modal-box {}", class); 56 | rsx!( 57 | div { 58 | class: "{class}", 59 | {props.children} 60 | } 61 | ) 62 | } 63 | 64 | #[derive(Props, Clone, PartialEq)] 65 | pub struct ModalActionProps { 66 | children: Element, 67 | class: Option, 68 | } 69 | 70 | #[component] 71 | pub fn ModalAction(props: ModalActionProps) -> Element { 72 | let class = if let Some(class) = props.class { 73 | class 74 | } else { 75 | "".to_string() 76 | }; 77 | 78 | let class = format!("modal-action {}", class); 79 | rsx!( 80 | div { 81 | class: "{class}", 82 | {props.children} 83 | } 84 | ) 85 | } 86 | -------------------------------------------------------------------------------- /src/nav_item.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Props, Clone, PartialEq)] 5 | pub struct NavItemProps { 6 | href: String, 7 | icon: String, 8 | title: String, 9 | selected_item_id: Option, 10 | id: Option, 11 | } 12 | 13 | #[component] 14 | pub fn NavItem(props: NavItemProps) -> Element { 15 | let mut class = ""; 16 | if let (Some(id), Some(selected_item_id)) = (&props.id, &props.selected_item_id) { 17 | if id == selected_item_id { 18 | class = "active"; 19 | } 20 | } 21 | rsx!( 22 | li { 23 | role: "listitem", 24 | a { 25 | class: "{class}", 26 | href: "{props.href}", 27 | "data-turbo-frame": "main-content", 28 | img { 29 | width: "16", 30 | height: "16", 31 | src: "{props.icon}" 32 | } 33 | "{props.title}" 34 | } 35 | } 36 | ) 37 | } 38 | 39 | #[derive(Props, Clone, PartialEq)] 40 | pub struct NavSubItemProps { 41 | href: String, 42 | title: String, 43 | selected_item_id: Option, 44 | id: Option, 45 | } 46 | 47 | #[component] 48 | pub fn NavSubItem(props: NavSubItemProps) -> Element { 49 | let mut class = ""; 50 | if let (Some(id), Some(selected_item_id)) = (&props.id, &props.selected_item_id) { 51 | if id == selected_item_id { 52 | class = "active"; 53 | } 54 | } 55 | rsx!( 56 | li { 57 | class: class, 58 | a { 59 | href: "{props.href}", 60 | "{props.title}" 61 | } 62 | } 63 | ) 64 | } 65 | 66 | #[derive(Props, Clone, PartialEq)] 67 | pub struct NavGroupProps { 68 | heading: String, 69 | content: Element, 70 | } 71 | 72 | #[component] 73 | pub fn NavGroup(props: NavGroupProps) -> Element { 74 | rsx!( 75 | ul { 76 | role: "list", 77 | class: "menu", 78 | li { 79 | class: "menu-title", 80 | "{props.heading}" 81 | } 82 | {props.content} 83 | } 84 | ) 85 | } 86 | 87 | #[derive(Props, Clone, PartialEq)] 88 | pub struct NavSubGroupProps { 89 | children: Element, 90 | } 91 | 92 | #[component] 93 | pub fn NavSubGroup(props: NavSubGroupProps) -> Element { 94 | rsx!( 95 | ul { 96 | role: "list", 97 | class: "ActionList ActionList--subGroup", 98 | {props.children} 99 | } 100 | ) 101 | } 102 | -------------------------------------------------------------------------------- /src/pagination.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Props, Clone, PartialEq)] 5 | pub struct PaginationProps { 6 | next_page_url: Option, 7 | prev_page_url: Option, 8 | } 9 | 10 | #[component] 11 | pub fn Pagination(props: PaginationProps) -> Element { 12 | rsx!( 13 | nav { 14 | class: "paginate-container", 15 | "aria-label": "Pagination", 16 | div { 17 | class: "pagination", 18 | if let Some(url) = props.prev_page_url { 19 | a { 20 | class: "previous_page", 21 | rel: "previous", 22 | href: "{url}", 23 | "Previous" 24 | } 25 | } else { 26 | span { 27 | class: "previous_page", 28 | "aria-disabled": "true", 29 | "Previous" 30 | } 31 | } 32 | if let Some(url) = props.next_page_url { 33 | a { 34 | class: "next_page", 35 | rel: "next", 36 | href: "{url}", 37 | "Next" 38 | } 39 | } else { 40 | span { 41 | class: "next_page", 42 | "aria-disabled": "true", 43 | "Next" 44 | } 45 | } 46 | } 47 | } 48 | ) 49 | } 50 | -------------------------------------------------------------------------------- /src/range.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] 5 | pub enum RangeColor { 6 | #[default] 7 | Default, 8 | Warn, 9 | Info, 10 | Error, 11 | Success, 12 | } 13 | 14 | impl RangeColor { 15 | pub fn to_string(&self) -> &'static str { 16 | match self { 17 | RangeColor::Default => "range range-info", 18 | RangeColor::Info => "range range-info", 19 | RangeColor::Warn => "range range-warning", 20 | RangeColor::Error => "range range-error", 21 | RangeColor::Success => "range range-success", 22 | } 23 | } 24 | } 25 | 26 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 27 | pub enum RangeSize { 28 | #[default] 29 | Default, 30 | Small, 31 | ExtraSmall, 32 | Large, 33 | Medium, 34 | } 35 | 36 | impl RangeSize { 37 | pub fn to_string(&self) -> &'static str { 38 | match self { 39 | RangeSize::Default => "range-sm", 40 | RangeSize::ExtraSmall => "range-xs", 41 | RangeSize::Small => "range-sm", 42 | RangeSize::Large => "range-lg", 43 | RangeSize::Medium => "range-md", 44 | } 45 | } 46 | } 47 | 48 | #[derive(Props, Clone, PartialEq)] 49 | pub struct RangeProps { 50 | children: Element, 51 | class: Option, 52 | min: i32, 53 | max: i32, 54 | value: i32, 55 | name: String, 56 | label: Option, 57 | label_class: Option, 58 | help_text: Option, 59 | range_color: Option, 60 | } 61 | 62 | #[component] 63 | pub fn Range(props: RangeProps) -> Element { 64 | let range_color = if props.range_color.is_some() { 65 | props.range_color.unwrap() 66 | } else { 67 | Default::default() 68 | }; 69 | 70 | let class = if let Some(class) = props.class { 71 | class 72 | } else { 73 | "".to_string() 74 | }; 75 | 76 | let class = format!("{} {}", range_color.to_string(), class); 77 | 78 | rsx!( 79 | match props.label { 80 | Some(l) => rsx!( 81 | label { 82 | class: props.label_class, 83 | "{l}" 84 | } 85 | ), 86 | None => rsx!() 87 | } 88 | input { 89 | "type": "range", 90 | min: "{props.min}", 91 | max: "{props.max}", 92 | value: "{props.value}", 93 | class: "{class}", 94 | name: props.name, 95 | {props.children}, 96 | } 97 | match props.help_text { 98 | Some(l) => rsx!( 99 | label { 100 | span { 101 | class: "label-text-alt", 102 | "{l}" 103 | } 104 | } 105 | ), 106 | None => rsx!() 107 | } 108 | ) 109 | } 110 | -------------------------------------------------------------------------------- /src/relative_time.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 5 | pub enum RelativeTimeFormat { 6 | Datetime, 7 | #[default] 8 | Relative, 9 | Duration, 10 | Auto, 11 | Micro, 12 | Elapsed, 13 | } 14 | 15 | impl RelativeTimeFormat { 16 | pub fn to_string(&self) -> &'static str { 17 | match self { 18 | RelativeTimeFormat::Datetime => "datetime", 19 | RelativeTimeFormat::Relative => "relative", 20 | RelativeTimeFormat::Duration => "duration", 21 | RelativeTimeFormat::Auto => "auto", 22 | RelativeTimeFormat::Micro => "micro", 23 | RelativeTimeFormat::Elapsed => "elapsed", 24 | } 25 | } 26 | } 27 | 28 | #[derive(Props, Clone, PartialEq)] 29 | pub struct RelativeTimeProps { 30 | format: Option, 31 | datetime: String, 32 | } 33 | 34 | #[component] 35 | pub fn RelativeTime(props: RelativeTimeProps) -> Element { 36 | let format = if props.format.is_some() { 37 | props.format.unwrap() 38 | } else { 39 | Default::default() 40 | }; 41 | 42 | rsx!( 43 | relative 44 | - time { 45 | datetime: props.datetime, 46 | format: format.to_string() 47 | } 48 | ) 49 | } 50 | -------------------------------------------------------------------------------- /src/select.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 5 | pub enum SelectSize { 6 | #[default] 7 | Default, 8 | Small, 9 | ExtraSmall, 10 | Large, 11 | Medium, 12 | } 13 | 14 | impl SelectSize { 15 | pub fn to_string(&self) -> &'static str { 16 | match self { 17 | SelectSize::Default => "select-sm", 18 | SelectSize::Small => "select-sm", 19 | SelectSize::ExtraSmall => "select-xs", 20 | SelectSize::Large => "select-lg", 21 | SelectSize::Medium => "select-md", 22 | } 23 | } 24 | } 25 | 26 | #[derive(Props, Clone, PartialEq)] 27 | pub struct SelectProps { 28 | children: Element, 29 | select_size: Option, 30 | pub name: String, 31 | pub id: Option, 32 | pub value: Option, 33 | pub label: Option, 34 | pub label_class: Option, 35 | pub help_text: Option, 36 | pub required: Option, 37 | pub disabled: Option, 38 | pub multiple: Option, 39 | } 40 | 41 | #[component] 42 | pub fn Select(props: SelectProps) -> Element { 43 | let select_size = if props.select_size.is_some() { 44 | props.select_size.unwrap() 45 | } else { 46 | Default::default() 47 | }; 48 | 49 | let value = props.value.unwrap_or("".to_string()); 50 | 51 | let class = select_size.to_string(); 52 | 53 | let disabled = if let Some(disabled) = props.disabled { 54 | if disabled { 55 | Some(true) 56 | } else { 57 | None 58 | } 59 | } else { 60 | None 61 | }; 62 | 63 | rsx!( 64 | match props.label { 65 | Some(l) => rsx!( 66 | label { 67 | class: props.label_class, 68 | "{l}" 69 | } 70 | ), 71 | None => rsx!() 72 | } 73 | select { 74 | id: props.id, 75 | required: props.required, 76 | disabled: disabled, 77 | multiple: props.multiple, 78 | class: "select select-bordered {class}", 79 | value: "{value}", 80 | name: "{props.name}", 81 | {props.children} 82 | } 83 | match props.help_text { 84 | Some(l) => rsx!( 85 | label { 86 | class: "label-text-alt", 87 | span { 88 | "{l}" 89 | } 90 | } 91 | ), 92 | None => rsx!() 93 | } 94 | ) 95 | } 96 | 97 | #[derive(Props, Clone, PartialEq)] 98 | pub struct OptionProps { 99 | children: Element, 100 | pub value: String, 101 | pub selected_value: Option, 102 | } 103 | 104 | #[component] 105 | pub fn SelectOption(props: OptionProps) -> Element { 106 | if let Some(selected) = props.selected_value { 107 | if selected == props.value { 108 | return rsx!( 109 | option { 110 | value: props.value, 111 | selected: true, 112 | {props.children} 113 | } 114 | ); 115 | } 116 | } 117 | rsx!( 118 | option { 119 | value: props.value, 120 | {props.children} 121 | } 122 | ) 123 | } 124 | -------------------------------------------------------------------------------- /src/tab_container.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(unused_braces)] 3 | 4 | use dioxus::prelude::*; 5 | 6 | #[derive(Props, Clone, PartialEq)] 7 | pub struct TabContainerProps { 8 | class: Option, 9 | children: Element, 10 | } 11 | 12 | #[component] 13 | pub fn TabContainer(props: TabContainerProps) -> Element { 14 | let class = if let Some(class) = props.class { 15 | class 16 | } else { 17 | "".to_string() 18 | }; 19 | 20 | rsx!( 21 | div { 22 | role: "tablist", 23 | class: "tabs tabs-bordered {class}", 24 | {{props.children}} 25 | } 26 | ) 27 | } 28 | 29 | #[derive(Props, Clone, PartialEq)] 30 | pub struct TabPanelProps { 31 | name: String, 32 | checked: Option, 33 | tab_name: String, 34 | children: Element, 35 | } 36 | 37 | #[component] 38 | pub fn TabPanel(props: TabPanelProps) -> Element { 39 | rsx!( 40 | input { 41 | checked: props.checked, 42 | "type": "radio", 43 | class: "tab", 44 | "aria-label": props.tab_name, 45 | name: props.name 46 | } 47 | div { 48 | role: "tabpanel", 49 | class: "tab-content", 50 | {{props.children}} 51 | } 52 | ) 53 | } 54 | -------------------------------------------------------------------------------- /src/text_area.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 5 | pub enum TextAreaSize { 6 | #[default] 7 | Default, 8 | Small, 9 | ExtraSmall, 10 | Large, 11 | Medium, 12 | } 13 | 14 | impl TextAreaSize { 15 | pub fn to_string(&self) -> &'static str { 16 | match self { 17 | TextAreaSize::Default => "textarea-sm", 18 | TextAreaSize::Small => "textarea-sm", 19 | TextAreaSize::ExtraSmall => "textarea-xs", 20 | TextAreaSize::Large => "textarea-lg", 21 | TextAreaSize::Medium => "textarea-md", 22 | } 23 | } 24 | } 25 | 26 | #[derive(Props, Clone, PartialEq)] 27 | pub struct Props { 28 | children: Element, 29 | area_size: Option, 30 | pub name: String, 31 | pub id: Option, 32 | pub class: Option, 33 | pub rows: Option, 34 | pub label_class: Option, 35 | pub value: Option, 36 | pub label: Option, 37 | pub help_text: Option, 38 | pub placeholder: Option, 39 | pub required: Option, 40 | pub disabled: Option, 41 | pub readonly: Option, 42 | } 43 | 44 | #[component] 45 | pub fn TextArea(props: Props) -> Element { 46 | let input_size = if props.area_size.is_some() { 47 | props.area_size.unwrap() 48 | } else { 49 | Default::default() 50 | }; 51 | 52 | let class = if props.class.is_some() { 53 | format!("{} {}", props.class.unwrap(), input_size.to_string()) 54 | } else { 55 | input_size.to_string().to_string() 56 | }; 57 | 58 | let value = props.value.unwrap_or("".to_string()); 59 | 60 | let placeholder = if props.placeholder.is_some() { 61 | props.placeholder.unwrap() 62 | } else { 63 | "".to_string() 64 | }; 65 | 66 | let label_class = if let Some(label_class) = props.label_class { 67 | label_class 68 | } else { 69 | "".to_string() 70 | }; 71 | 72 | let disabled = if let Some(disabled) = props.disabled { 73 | if disabled { 74 | Some(true) 75 | } else { 76 | None 77 | } 78 | } else { 79 | None 80 | }; 81 | 82 | let id = if let Some(id) = props.id { 83 | id 84 | } else { 85 | "".to_string() 86 | }; 87 | 88 | rsx!( 89 | match props.label { 90 | Some(l) => rsx!( 91 | label { 92 | class: "{label_class}", 93 | "{l}" 94 | } 95 | ), 96 | None => rsx!() 97 | } 98 | textarea { 99 | id: "{id}", 100 | class: "textarea textarea-bordered textarea-sm {class}", 101 | value: "{value}", 102 | name: "{props.name}", 103 | placeholder: "{placeholder}", 104 | required: props.required, 105 | disabled: disabled, 106 | readonly: props.readonly, 107 | rows: props.rows, 108 | {props.children}, 109 | } 110 | match props.help_text { 111 | Some(l) => rsx!( 112 | span { 113 | class: "note mb-3", 114 | "{l}" 115 | } 116 | ), 117 | None => rsx!() 118 | } 119 | ) 120 | } 121 | -------------------------------------------------------------------------------- /src/time_line.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(unused_braces)] 3 | 4 | use dioxus::prelude::*; 5 | 6 | #[derive(Props, Clone, PartialEq)] 7 | pub struct TimeLineProps { 8 | condensed: Option, 9 | class: Option, 10 | children: Element, 11 | } 12 | 13 | #[component] 14 | pub fn TimeLine(props: TimeLineProps) -> Element { 15 | let class = if let Some(class) = props.class { 16 | class 17 | } else { 18 | "".to_string() 19 | }; 20 | 21 | let the_class = format!("timeline-item {}", class); 22 | 23 | let class = if props.condensed.is_some() { 24 | format!("timeline-condensed {}", the_class) 25 | } else { 26 | the_class 27 | }; 28 | 29 | rsx!( 30 | div { 31 | class: "{class}", 32 | {{props.children}} 33 | } 34 | ) 35 | } 36 | 37 | #[derive(Props, Clone, PartialEq)] 38 | pub struct TimeLineBadgeProps { 39 | image_src: String, 40 | class: Option, 41 | } 42 | 43 | #[component] 44 | pub fn TimeLineBadge(props: TimeLineBadgeProps) -> Element { 45 | let class = if let Some(class) = props.class { 46 | class 47 | } else { 48 | "".to_string() 49 | }; 50 | 51 | let class = format!("timeline-badge {}", class); 52 | rsx!( 53 | div { 54 | class: "{class}", 55 | img { 56 | src: "{props.image_src}", 57 | width: "16" 58 | } 59 | } 60 | ) 61 | } 62 | 63 | #[derive(Props, Clone, PartialEq)] 64 | pub struct TimeLineBodyProps { 65 | children: Element, 66 | class: Option, 67 | } 68 | 69 | #[component] 70 | pub fn TimeLineBody(props: TimeLineBodyProps) -> Element { 71 | let class = if let Some(class) = props.class { 72 | class 73 | } else { 74 | "".to_string() 75 | }; 76 | 77 | let class = format!("timeline-body {}", class); 78 | 79 | rsx!( 80 | div { 81 | class: "{class}", 82 | {props.children} 83 | } 84 | ) 85 | } 86 | -------------------------------------------------------------------------------- /src/tooltip.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | 4 | #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] 5 | pub enum ToolTipColor { 6 | #[default] 7 | Default, 8 | Warn, 9 | Info, 10 | Error, 11 | Success, 12 | } 13 | 14 | impl ToolTipColor { 15 | pub fn to_string(&self) -> &'static str { 16 | match self { 17 | ToolTipColor::Default => "tooltip tooltip-info", 18 | ToolTipColor::Info => "tooltip tooltip-info", 19 | ToolTipColor::Warn => "tooltip tooltip-warning", 20 | ToolTipColor::Error => "tooltip tooltip-error", 21 | ToolTipColor::Success => "tooltip tooltip-success", 22 | } 23 | } 24 | } 25 | 26 | #[derive(Props, Clone, PartialEq)] 27 | pub struct ToolTipProps { 28 | text: String, 29 | children: Element, 30 | class: Option, 31 | alert_color: Option, 32 | } 33 | 34 | #[component] 35 | pub fn ToolTip(props: ToolTipProps) -> Element { 36 | let alert_color = if props.alert_color.is_some() { 37 | props.alert_color.unwrap() 38 | } else { 39 | Default::default() 40 | }; 41 | 42 | let class = if let Some(class) = props.class { 43 | class 44 | } else { 45 | "".to_string() 46 | }; 47 | 48 | let class = format!("{} {}", alert_color.to_string(), class); 49 | 50 | rsx!( 51 | div { 52 | class: "{class}", 53 | "data-tip": props.text, 54 | {props.children} 55 | } 56 | ) 57 | } 58 | --------------------------------------------------------------------------------