├── examples └── htmx-rsx │ ├── .gitignore │ ├── tailwind.css │ ├── src │ ├── views │ │ ├── mod.rs │ │ ├── home.rs │ │ ├── about.rs │ │ ├── list.rs │ │ ├── document.rs │ │ └── nav.rs │ ├── main.rs │ └── handlers.rs │ ├── Cargo.toml │ ├── build.rs │ └── README.md ├── hypertext-macros ├── src │ ├── html │ │ ├── syntaxes │ │ │ ├── mod.rs │ │ │ ├── maud.rs │ │ │ └── rsx.rs │ │ ├── component.rs │ │ ├── control.rs │ │ ├── basics.rs │ │ └── generate.rs │ ├── lib.rs │ ├── component.rs │ └── derive.rs └── Cargo.toml ├── rustfmt.toml ├── deny.toml ├── .github ├── dependabot.yaml └── workflows │ ├── security-audit.yaml │ └── ci.yaml ├── hypertext ├── src │ ├── prelude.rs │ ├── context.rs │ ├── macros │ │ ├── mod.rs │ │ └── alloc.rs │ ├── validation │ │ ├── mathml.rs │ │ ├── mod.rs │ │ └── attributes.rs │ ├── web_frameworks.rs │ ├── alloc │ │ ├── impls.rs │ │ └── mod.rs │ └── lib.rs ├── Cargo.toml └── tests │ └── main.rs ├── Cargo.toml ├── LICENSE.txt ├── release-plz.toml ├── README.md ├── .gitignore └── CHANGELOG.md /examples/htmx-rsx/.gitignore: -------------------------------------------------------------------------------- 1 | static/ 2 | -------------------------------------------------------------------------------- /examples/htmx-rsx/tailwind.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | -------------------------------------------------------------------------------- /hypertext-macros/src/html/syntaxes/mod.rs: -------------------------------------------------------------------------------- 1 | mod maud; 2 | mod rsx; 3 | 4 | pub use self::{maud::Maud, rsx::Rsx}; 5 | -------------------------------------------------------------------------------- /examples/htmx-rsx/src/views/mod.rs: -------------------------------------------------------------------------------- 1 | mod about; 2 | mod document; 3 | mod home; 4 | mod list; 5 | mod nav; 6 | 7 | pub use self::{about::*, document::*, home::*, list::*, nav::*}; 8 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | unstable_features = true 2 | format_code_in_doc_comments = true 3 | format_macro_matchers = true 4 | group_imports = "StdExternalCrate" 5 | imports_granularity = "Crate" 6 | reorder_impl_items = true 7 | wrap_comments = true 8 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | [licenses] 2 | allow = ["Apache-2.0", "BSD-3-Clause", "MIT", "Unicode-3.0", "Zlib"] 3 | 4 | [advisories] 5 | ignore = [ 6 | "RUSTSEC-2020-0056", 7 | "RUSTSEC-2021-0059", 8 | "RUSTSEC-2021-0060", 9 | "RUSTSEC-2021-0064", 10 | "RUSTSEC-2024-0384", 11 | ] 12 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: "cargo" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | 9 | - package-ecosystem: "github-actions" 10 | directory: "/" 11 | schedule: 12 | interval: "daily" 13 | -------------------------------------------------------------------------------- /examples/htmx-rsx/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "htmx-rsx" 3 | 4 | edition.workspace = true 5 | license.workspace = true 6 | publish = false 7 | version = "0.0.0" 8 | 9 | [dependencies] 10 | anyhow = "1" 11 | axum = "0.8" 12 | axum-htmx = "0.8" 13 | hypertext = { path = "../../hypertext", features = ["axum", "htmx"] } 14 | tokio = { version = "1", features = ["macros", "rt-multi-thread"] } 15 | tower-http = { version = "0.6", features = ["fs"] } 16 | -------------------------------------------------------------------------------- /examples/htmx-rsx/src/views/home.rs: -------------------------------------------------------------------------------- 1 | use hypertext::prelude::*; 2 | 3 | #[component] 4 | pub fn home() -> impl Renderable { 5 | rsx! { 6 |
7 |

"Welcome to HTMX-RSX"

8 |

"This is a simple example of using HTMX with RSX."

9 |

"Click the links in the navigation bar to explore."

10 |
11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/htmx-rsx/src/views/about.rs: -------------------------------------------------------------------------------- 1 | use hypertext::prelude::*; 2 | 3 | #[component] 4 | pub fn about() -> impl Renderable { 5 | rsx! { 6 |
7 |

"About HTMX-RSX"

8 |

"HTMX-RSX is a simple example of using HTMX with RSX."

9 |

"This project demonstrates how to use HTMX for dynamic content loading in a Rust web application."

10 |
11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.github/workflows/security-audit.yaml: -------------------------------------------------------------------------------- 1 | name: Security Audit 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | 7 | push: 8 | paths: 9 | - "**/Cargo.toml" 10 | - "**/Cargo.lock" 11 | - "**/deny.toml" 12 | 13 | pull_request: 14 | 15 | jobs: 16 | cargo-deny: 17 | name: Security Audit 18 | 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | 25 | - name: Run `cargo-deny` 26 | uses: EmbarkStudios/cargo-deny-action@v2 27 | -------------------------------------------------------------------------------- /examples/htmx-rsx/src/views/list.rs: -------------------------------------------------------------------------------- 1 | use hypertext::prelude::*; 2 | 3 | #[component] 4 | pub fn list() -> impl Renderable { 5 | let list_items = vec!["Hypertext", "is", "fun!"]; 6 | rsx! { 7 |
8 |

"Loop through items using Rust code!"

9 | 14 |
15 | } 16 | } 17 | -------------------------------------------------------------------------------- /hypertext/src/prelude.rs: -------------------------------------------------------------------------------- 1 | //! Re-exported items for convenience. 2 | //! 3 | //! This module re-exports all the commonly used items from the crate, 4 | //! so you can use them without having to import them individually. It also 5 | //! re-exports the [`hypertext_elements`] module, and any [framework-specific 6 | //! attribute traits](crate::validation::attributes) that have been enabled, as 7 | //! well as the [`GlobalAttributes`] trait. 8 | pub use crate::validation::{attributes::*, hypertext_elements}; 9 | #[cfg(feature = "alloc")] 10 | pub use crate::{Renderable, RenderableExt as _, Rendered, attribute, component, maud, rsx}; 11 | -------------------------------------------------------------------------------- /hypertext-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hypertext-macros" 3 | version.workspace = true 4 | authors.workspace = true 5 | edition.workspace = true 6 | description.workspace = true 7 | documentation = "https://docs.rs/hypertext-macros" 8 | readme.workspace = true 9 | homepage.workspace = true 10 | repository.workspace = true 11 | license.workspace = true 12 | keywords.workspace = true 13 | categories.workspace = true 14 | 15 | [lib] 16 | proc-macro = true 17 | 18 | [dependencies] 19 | html-escape.workspace = true 20 | proc-macro2 = "1" 21 | quote = "1" 22 | syn = { version = "2", features = ["extra-traits", "full"] } 23 | 24 | [lints] 25 | workspace = true 26 | 27 | -------------------------------------------------------------------------------- /examples/htmx-rsx/build.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, process::Command}; 2 | 3 | const TAILWIND_CSS: &str = "tailwind.css"; 4 | 5 | fn main() -> Result<(), Box> { 6 | println!("cargo:rerun-if-changed={TAILWIND_CSS}"); 7 | println!("cargo:rerun-if-changed=src/views/"); 8 | 9 | let output = Command::new("tailwindcss") 10 | .args(["-i", TAILWIND_CSS, "-o", "static/styles.css", "--minify"]) 11 | .output()?; 12 | 13 | if !output.status.success() { 14 | return Err(format!( 15 | "failed to execute `tailwindcss`:\n{}", 16 | String::from_utf8_lossy(&output.stderr) 17 | ) 18 | .into()); 19 | } 20 | 21 | Ok(()) 22 | } 23 | -------------------------------------------------------------------------------- /examples/htmx-rsx/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::net::Ipv4Addr; 2 | 3 | use anyhow::Result; 4 | use axum::{Router, routing::get}; 5 | use handlers::{handle_about, handle_home, handle_list}; 6 | use tokio::net::TcpListener; 7 | use tower_http::services::ServeDir; 8 | 9 | mod handlers; 10 | mod views; 11 | 12 | #[tokio::main] 13 | async fn main() -> Result<()> { 14 | // build our application with a route 15 | let app = Router::new() 16 | .route("/", get(handle_home)) 17 | .route("/about", get(handle_about)) 18 | .route("/list", get(handle_list)) 19 | .fallback_service(ServeDir::new("static")); 20 | 21 | // run our app with hyper, listening globally on port 3000 22 | let listener = TcpListener::bind((Ipv4Addr::UNSPECIFIED, 3000)).await?; 23 | 24 | axum::serve(listener, app).await?; 25 | 26 | Ok(()) 27 | } 28 | -------------------------------------------------------------------------------- /examples/htmx-rsx/src/handlers.rs: -------------------------------------------------------------------------------- 1 | use axum::response::IntoResponse; 2 | use axum_htmx::HxRequest; 3 | use hypertext::prelude::*; 4 | 5 | use crate::views::{Document, Nav, about, home, list}; 6 | 7 | fn maybe_document( 8 | HxRequest(is_hx_request): HxRequest, 9 | selected: &str, 10 | children: R, 11 | ) -> impl IntoResponse { 12 | rsx! { 13 | @if is_hx_request { 14 |