Headings
Rust UI component that displays a heading with premade styles and animations.
headings
Heading 1
Heading 2
Heading 3
Heading 4
use leptos::prelude::*; use crate::components::ui::headings::{H1, H2, H3, H4}; #[component] pub fn DemoHeadings() -> impl IntoView { view! { <div> <H1>"Heading 1"</H1> <H2>"Heading 2"</H2> <H3>"Heading 3"</H3> <H4>"Heading 4"</H4> </div> } }
Demos
1. Headings Variants
Modern
Underline
use leptos::prelude::*; use crate::components::ui::headings::{H3, HeadingVariant}; #[component] pub fn DemoHeadingsVariants() -> impl IntoView { view! { <div class="flex flex-col gap-2"> <H3 variant=HeadingVariant::Modern>"Modern"</H3> <H3 variant=HeadingVariant::Underline>"Underline"</H3> </div> } }
2. Headings Animate
This is a Heading using Animate
use leptos::prelude::*; use crate::components::ui::animate::{Animate, AnimateVariant}; use crate::components::ui::headings::H1; #[component] pub fn DemoHeadingsAnimate() -> impl IntoView { view! { <Animate variant=AnimateVariant::FadeUp style="animation-delay: 0.25s; animation-fill-mode: forwards;" > <H1>"This is a Heading using Animate"</H1> </Animate> } }
Installation
You can run either of the following commands:
# cargo install ui-cli --forceui add demo_headingsui add headings
Update the imports to match your project setup.
Copy and paste the following code into your project:
components/ui/headings.rs
use leptos::prelude::*; use tw_merge::*; // TODO 🐛 tw_merge!() working for all except what's inside (text-3xl, text-2xl, etc.) // TODO. └──> I tried different way of doing this (cf. H1 and H2), but not working // TODO 💪 Export Motion to _shared.rs (not working yet with #[tw(class = ...)] typically that do not support expanding constants directly) #[derive(TwClass, Default)] #[tw(class = "font-bold text-pretty")] pub struct Heading { variant: HeadingVariant, } #[component] pub fn H1( #[prop(into, optional)] variant: Signal<HeadingVariant>, #[prop(into, optional)] class: Signal<String>, #[prop(into, optional)] style: Signal<String>, children: Children, ) -> impl IntoView { let class = Memo::new(move |_| { let variant = variant.get(); let heading = Heading { variant }; tw_merge!(heading.with_class(class.get()), "text-4xl") }); view! { <h1 class=class style=style> {children()} </h1> } } #[component] pub fn H2( #[prop(into, optional)] variant: Signal<HeadingVariant>, #[prop(into, optional)] class: Signal<String>, children: Children, ) -> impl IntoView { let class = Memo::new(move |_| { let variant = variant.get(); let heading = Heading { variant }; tw_merge!(heading.with_class(class.get()), "text-3xl") }); view! { <h2 class=class>{children()}</h2> } } #[component] pub fn H3( #[prop(into, optional)] variant: Signal<HeadingVariant>, #[prop(into, optional)] class: Signal<String>, children: Children, ) -> impl IntoView { let class = Memo::new(move |_| { let variant = variant.get(); let heading = Heading { variant }; tw_merge!(heading.with_class(class.get()), "text-2xl") }); view! { <h3 class=class>{children()}</h3> } } #[component] pub fn H4( #[prop(into, optional)] variant: Signal<HeadingVariant>, #[prop(into, optional)] class: Signal<String>, children: Children, ) -> impl IntoView { let class = Memo::new(move |_| { let variant = variant.get(); let heading = Heading { variant }; tw_merge!(heading.with_class(class.get()), "text-xl") }); view! { <h4 class=class>{children()}</h4> } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 🧬 STRUCT 🧬 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ✨ FUNCTIONS ✨ */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ #[derive(TwVariant)] pub enum HeadingVariant { #[tw(default, class = "text-pretty")] Default, #[tw( class = "tracking-tighter text-transparent bg-gradient-to-r from-white to-gray-500 bg-clip-text" )] Modern, #[tw( class = "underline underline-offset-3 decoration-8 decoration-neutral-400 dark:decoration-neutral-600" )] Underline, }
Update the imports to match your project setup.
Usage
// Coming soon 🦀