This commit is contained in:
JMARyA 2025-01-15 18:28:59 +01:00
parent 8208fa8899
commit ed739d792f
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
35 changed files with 1675 additions and 447 deletions

View file

@ -1,134 +1,46 @@
use maud::{Markup, PreEscaped, Render, html};
pub mod appbar;
pub mod aspect;
pub mod background;
pub mod container;
pub mod div;
pub mod flex;
pub mod header;
pub mod image;
pub mod link;
pub mod padding;
pub mod rounded;
pub mod search;
pub mod shadow;
pub mod sized;
pub mod text;
pub mod width;
use components::Shell;
use maud::{Markup, PreEscaped, Render};
// UI
// Preludes
// Basic Primitives
pub mod basic {
pub use super::aspect::Aspect;
pub use super::background::Background;
pub use super::background::{Blue, Gray};
pub use super::container::Container;
pub use super::div::Div;
pub use super::flex::Flex;
pub use super::flex::Justify;
pub use super::header::Header;
pub use super::image::Image;
pub use super::link::Link;
pub use super::padding::Padding;
pub use super::rounded::Rounded;
pub use super::rounded::RoundedMedium;
pub use super::shadow::Shadow;
pub use super::sized::Sized;
pub use super::text::{Paragraph, Span, Text};
pub use super::width::FitWidth;
}
pub mod color;
pub mod htmx;
pub mod primitives;
pub mod wrapper;
// Stacked Components
pub mod extended {
pub use super::appbar::AppBar;
pub mod components;
// Preludes
pub mod prelude {
pub use super::color::*;
pub use super::primitives::Nothing;
pub use super::primitives::Side;
pub use super::primitives::Size;
pub use super::primitives::aspect::Aspect;
pub use super::primitives::background::Background;
pub use super::primitives::container::Container;
pub use super::primitives::div::Div;
pub use super::primitives::flex::{Flex, Justify};
pub use super::primitives::header::Header;
pub use super::primitives::image::Image;
pub use super::primitives::link::Link;
pub use super::primitives::padding::Padding;
pub use super::primitives::rounded::Rounded;
pub use super::primitives::script;
pub use super::primitives::shadow::Shadow;
pub use super::primitives::sized::Sized;
pub use super::primitives::space::{ScreenValue, SpaceBetween};
pub use super::primitives::text::{Paragraph, Span, Text};
pub use super::primitives::width::FitWidth;
pub use super::wrapper::Hover;
}
use crate::request::{RequestContext, StringResponse};
use rocket::http::{ContentType, Status};
#[allow(non_snake_case)]
pub fn Nothing() -> PreEscaped<String> {
html! {}
}
/// Represents the HTML structure of a page shell, including the head, body class, and body content.
///
/// This structure is used to construct the overall HTML structure of a page, making it easier to generate consistent HTML pages dynamically.
pub struct Shell {
/// The HTML content for the `<head>` section of the page.
head: PreEscaped<String>,
/// An optional class attribute for the `<body>` element.
body_class: Option<String>,
/// The HTML content for the static body portion.
body_content: PreEscaped<String>,
}
impl Shell {
/// Constructs a new `Shell` instance with the given head content, body content, and body class.
///
/// # Arguments
/// * `head` - The HTML content for the page's head.
/// * `body_content` - The HTML content for the body of the page.
/// * `body_class` - An optional class to apply to the `<body>` element.
///
/// # Returns
/// A `Shell` instance encapsulating the provided HTML content and attributes.
#[must_use]
pub const fn new(
head: PreEscaped<String>,
body_content: PreEscaped<String>,
body_class: Option<String>,
) -> Self {
Self {
head,
body_class,
body_content,
}
}
/// Renders the full HTML page using the shell structure, with additional content and a title.
///
/// # Arguments
/// * `content` - The additional HTML content to render inside the main content div.
/// * `title` - The title of the page, rendered inside the `<title>` element.
///
/// # Returns
/// A `PreEscaped<String>` containing the full HTML page content.
#[must_use]
pub fn render(&self, content: PreEscaped<String>, title: &str) -> PreEscaped<String> {
html! {
html {
head {
title { (title) };
(self.head)
};
@if self.body_class.is_some() {
body class=(self.body_class.as_ref().unwrap()) {
(self.body_content);
div id="main_content" {
(content)
};
};
} @else {
body {
(self.body_content);
div id="main_content" {
(content)
};
};
}
}
}
}
}
/// Renders a full page or an HTMX-compatible fragment based on the request context.
///
/// If the request is not an HTMX request, this function uses the provided shell to generate
@ -161,61 +73,6 @@ pub async fn render_page(
}
}
/// Generates an HTML link with HTMX attributes for dynamic behavior.
///
/// This function creates an `<a>` element with attributes that enable HTMX behavior for navigation without reload.
///
/// # Arguments
/// * `url` - The URL to link to.
/// * `class` - The CSS class for styling the link.
/// * `onclick` - The JavaScript `onclick` handler for the link.
/// * `content` - The content inside the link element.
///
/// # Returns
/// A `PreEscaped<String>` containing the rendered HTML link element.
#[must_use]
pub fn htmx_link(
url: &str,
class: &str,
onclick: &str,
content: PreEscaped<String>,
) -> PreEscaped<String> {
html!(
a class=(class) onclick=(onclick) href=(url) hx-get=(url) hx-target="#main_content" hx-push-url="true" hx-swap="innerHTML" {
(content);
};
)
}
/// Generates a `<script>` element containing the provided JavaScript code.
///
/// This function wraps the provided JavaScript code in a `<script>` tag,
/// allowing for easy inclusion of custom scripts in the rendered HTML.
///
/// # Arguments
/// * `script` - The JavaScript code to include.
///
/// # Returns
/// A `PreEscaped<String>` containing the rendered `<script>` element.
#[must_use]
pub fn script(script: &str) -> PreEscaped<String> {
html!(
script {
(PreEscaped(script))
};
)
}
pub struct Row(PreEscaped<String>);
impl Render for Row {
fn render(&self) -> maud::Markup {
html! {
div class="flex" { (self.0) }
}
}
}
// Grids
// ListViews
@ -224,23 +81,40 @@ impl Render for Row {
// Cards
/// Generic UI Widget
pub trait UIWidget: Render {
/// Indicating if the widget supports inheriting classes
fn can_inherit(&self) -> bool;
/// Returning the base classes for this widget
fn base_class(&self) -> Vec<String>;
fn extended_class(&self) -> Vec<String>;
/// Render the widget with additional classes
fn render_with_class(&self, class: &str) -> Markup;
}
/// Implementation for raw HTML with html! macro
impl UIWidget for PreEscaped<String> {
fn can_inherit(&self) -> bool {
false
}
fn base_class(&self) -> Vec<String> {
vec![]
}
fn extended_class(&self) -> Vec<String> {
vec![]
}
fn render_with_class(&self, _: &str) -> Markup {
self.render()
}
}
// TODO :
// hover focus
// responsive media
// more elements
// htmx builder trait?
/// Trait for an element which can add new `attrs`
pub trait AttrExtendable {
fn add_attr(self, key: &str, val: &str) -> Self;
/// Set the `id` attribute of an element.
fn id(self, id: &str) -> Self;
}