Grid Collection
Rust UI component that displays a grid collection.
Groceries
$80.00
Groceries
$80.00
Groceries
$80.00
Groceries
$80.00
Daily Needs
4 items
Electricity
$80.00
Water
$80.00
Internet
$80.00
Utilities
3 items
Streaming
$80.00
Courses
$80.00
Software
$80.00
Streaming
$80.00
Subscriptions
4 items
use leptos::prelude::*; use leptos_meta::Stylesheet; use crate::components::extensions::grid_collection::{ Content, GridCollection, GridItem, Icon, IconGrid, ItemContent, }; // TODO. Default Trait #[derive(Clone)] struct GridItem { title: String, subtitle: String, transition_index: i32, items: Vec<Item>, } #[derive(Clone)] struct Item { title: String, price: String, transition_index: i32, chevron_index: i32, } #[component] pub fn DemoGridCollection() -> impl IntoView { let grid_items = vec![ GridItem { title: "Daily Needs".to_string(), subtitle: "4 items".to_string(), transition_index: 1, items: vec![ Item { title: "Groceries".to_string(), price: "$80.00".to_string(), transition_index: 1, chevron_index: 1, }, Item { title: "Groceries".to_string(), price: "$80.00".to_string(), transition_index: 2, chevron_index: 5, }, Item { title: "Groceries".to_string(), price: "$80.00".to_string(), transition_index: 3, chevron_index: 6, }, Item { title: "Groceries".to_string(), price: "$80.00".to_string(), transition_index: 4, chevron_index: 7, }, ], }, GridItem { title: "Utilities".to_string(), subtitle: "3 items".to_string(), transition_index: 2, items: vec![ Item { title: "Electricity".to_string(), price: "$80.00".to_string(), transition_index: 5, chevron_index: 2, }, Item { title: "Water".to_string(), price: "$80.00".to_string(), transition_index: 6, chevron_index: 9, }, Item { title: "Internet".to_string(), price: "$80.00".to_string(), transition_index: 7, chevron_index: 10, }, ], }, GridItem { title: "Subscriptions".to_string(), subtitle: "4 items".to_string(), transition_index: 3, items: vec![ Item { title: "Streaming".to_string(), price: "$80.00".to_string(), transition_index: 8, chevron_index: 3, }, Item { title: "Courses".to_string(), price: "$80.00".to_string(), transition_index: 9, chevron_index: 12, }, Item { title: "Software".to_string(), price: "$80.00".to_string(), transition_index: 10, chevron_index: 13, }, Item { title: "Streaming".to_string(), price: "$80.00".to_string(), transition_index: 11, chevron_index: 14, }, ], }, ]; view! { <Stylesheet id="grid-collection" href="/components/grid_collection.css" /> <script src="/components/grid_collection.js" /> <div class="font-sans max-w-[500px] my-10 mx-auto p-0 px-5 bg-white w-full h-[600px]"> <GridCollection> {grid_items .into_iter() .map(|item| { view! { <SharedGridItem title=item.title subtitle=item.subtitle transition_index=item.transition_index > {item .items .into_iter() .map(|shared_item| { view! { <SharedItem title=shared_item.title price=shared_item.price transition_index=shared_item.transition_index chevron_index=shared_item.chevron_index /> } }) .collect_view()} </SharedGridItem> } }) .collect_view()} </GridCollection> </div> } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ✨ FUNCTIONS ✨ */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ #[component] pub fn SharedGridItem( children: Children, title: String, subtitle: String, transition_index: i32, ) -> impl IntoView { let transition_grid_item = format!("view-transition-name: grid-item-{transition_index}"); let transition_grid_icon = format!("view-transition-name: icon-grid-{transition_index}"); let transition_name_content = format!("view-transition-name: content-{transition_index}"); let transition_name_title = format!("view-transition-name: title-{transition_index}"); let transition_name_close_icon = format!("view-transition-name: close-icon-{transition_index}"); let transition_name_count = format!("view-transition-name: count-{transition_index}"); let transition_name_chevron = format!("view-transition-name: chevron-{transition_index}"); // // const CLASS_CLOSE_ICON: &str = "close-icon flex items-center justify-center rounded-full size-6 bg-accent hidden"; view! { <GridItem style=transition_grid_item> <IconGrid style=transition_grid_icon>{children()}</IconGrid> <Content style=transition_name_content> <div class="text-base font-medium text-zinc-800 w-fit h-fit" style=transition_name_title > {title} </div> <div class=CLASS_CLOSE_ICON style=transition_name_close_icon> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" > <path d="M12 4L4 12M4 4l8 8" stroke-width="2" stroke-linecap="round" /> </svg> </div> <div class="displayNoneWhenExpanded text-muted-foreground" style=transition_name_count > {subtitle} </div> </Content> <div class="chevron" style=transition_name_chevron> <SvgChevron /> </div> </GridItem> } } #[component] pub fn SharedItem( title: String, price: String, transition_index: i32, chevron_index: i32, ) -> impl IntoView { let transition_title = format!("view-transition-name: item-title-{transition_index}"); let transition_price = format!("view-transition-name: item-price-{transition_index}"); let transition_item = format!("view-transition-name: item-{transition_index}"); let transition_icon = format!("view-transition-name: icon-{transition_index}"); let transition_chevron = format!("view-transition-name: chevron-{chevron_index}"); view! { <div class="item" style=transition_item> <Icon style=transition_icon> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"> <circle cx="12" cy="12" r="10" stroke-width="2" /> <path d="M10 8l6 4-6 4V8z" stroke-width="2" /> </svg> </Icon> <ItemContent> <div class="item-title" style=transition_title> {title} </div> <div class="item-price" style=transition_price> {price} </div> </ItemContent> <div class="chevron" style=transition_chevron> <SvgChevron /> </div> </div> } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ✨ FUNCTIONS ✨ */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ #[component] pub fn SvgChevron() -> impl IntoView { view! { <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"> <path d="M9 18l6-6-6-6" stroke-width="2" stroke-linecap="round" /> </svg> } }
Installation
# Coming soon :)
Usage
// Coming soon 🦀