Feat/collapse (#73)

* feat: add collapse component

* feat: collapse adds accordion prop

* fix(workflow): ci stable-cargo-leptos
This commit is contained in:
luoxiaozero 2024-01-09 14:32:13 +08:00 committed by GitHub
parent 1f889591ed
commit adcc0b6a54
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 179 additions and 0 deletions

View file

@ -65,4 +65,5 @@ jobs:
- name: Build
run: |
cd ./examples/ssr_axum
cargo install --locked cargo-leptos
cargo leptos build --release

View file

@ -53,6 +53,7 @@ fn TheRouter(is_routing: RwSignal<bool>) -> impl IntoView {
<Route path="/calendar" view=CalendarMdPage/>
<Route path="/card" view=CardMdPage/>
<Route path="/checkbox" view=CheckboxMdPage/>
<Route path="/collapse" view=CollapseMdPage/>
<Route path="/color-picker" view=ColorPickerMdPage/>
<Route path="/date-picker" view=DatePickerMdPage/>
<Route path="/divider" view=DividerMdPage/>

View file

@ -113,6 +113,10 @@ pub(crate) fn gen_menu_data() -> Vec<MenuGroupOption> {
value: "card".into(),
label: "Card".into(),
},
MenuItemOption {
value: "collapse".into(),
label: "Collapse".into(),
},
MenuItemOption {
value: "divider".into(),
label: "Divider".into(),

View file

@ -0,0 +1,53 @@
# Collapse
```rust demo
use std::collections::HashSet;
let value = create_rw_signal(HashSet::from(["thaw".to_string()]));
view! {
<Collapse value>
<CollapseItem title="Leptos" key="leptos">
"Build fast web applications with Rust."
</CollapseItem>
<CollapseItem title="Thaw" key="thaw">
"An easy to use leptos component library"
</CollapseItem>
</Collapse>
}
```
### Accordion
Like an accordion.
```rust demo
view! {
<Collapse accordion=true>
<CollapseItem title="Leptos" key="leptos">
"Build fast web applications with Rust."
</CollapseItem>
<CollapseItem title="Thaw" key="thaw">
"An easy to use leptos component library"
</CollapseItem>
</Collapse>
}
```
### Collapse Props
| Name | Type | Default | Description |
| --------- | --------------------------- | -------------------- | ------------------------------------------- |
| class | `MaybeSignal<String>` | `Default::default()` | Addtional classes for the collapse element. |
| value | `RwSignal<HashSet<String>>` | `Default::default()` | Currently active panel. |
| accordion | `bool` | `false` | Only allow one panel open at a time. |
| children | `Children` | | Collapse's content. |
### CollapseItem Props
| Name | Type | Default | Description |
| ------- | --------------------- | -------------------- | ------------------------------------------------ |
| class | `MaybeSignal<String>` | `Default::default()` | Addtional classes for the collapse item element. |
| title | `MaybeSignal<String>` | | The title of the CollapseItem. |
| key | `MaybeSignal<String>` | | The indentifier of CollapseItem. |
| chilren | `Children` | | CollapseItem's content. |

View file

@ -41,6 +41,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt
("CalendarMdPage", include_str!("../docs/calendar/mod.md")),
("CardMdPage", include_str!("../docs/card/mod.md")),
("CheckboxMdPage", include_str!("../docs/checkbox/mod.md")),
("CollapseMdPage", include_str!("../docs/collapse/mod.md")),
(
"ColorPickerMdPage",
include_str!("../docs/color_picker/mod.md"),

View file

@ -0,0 +1,22 @@
.thaw-collapse .thaw-collapse-item:not(:first-child) {
margin-top: 16px;
}
.thaw-collapse-item__header {
display: flex;
align-items: center;
cursor: pointer;
}
.thaw-collapse-item-arrow {
margin-right: 4px;
transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}
.thaw-collapse-item--active .thaw-collapse-item-arrow {
transform: rotate(90deg);
}
.thaw-collapse-item__content {
padding-top: 16px;
}

View file

@ -0,0 +1,62 @@
use super::use_collapse;
use crate::{
utils::{class_list::class_list, StoredMaybeSignal},
Icon,
};
use icondata::AiIcon;
use leptos::*;
#[component]
pub fn CollapseItem(
#[prop(optional, into)] class: MaybeSignal<String>,
#[prop(into)] title: MaybeSignal<String>,
#[prop(into)] key: MaybeSignal<String>,
children: Children,
) -> impl IntoView {
let collapse = use_collapse();
let key: StoredMaybeSignal<_> = key.into();
let is_show_content = create_memo(move |_| {
collapse.value.with(|keys| {
if key.with(|key| keys.contains(key)) {
true
} else {
false
}
})
});
let on_click = move |_| {
collapse.value.update(|keys| {
if collapse.accordion {
keys.clear();
}
let key = key.get_untracked();
if is_show_content.get_untracked() {
keys.remove(&key);
} else {
keys.insert(key);
}
});
};
view! {
<div class=class_list![
"thaw-collapse-item", ("thaw-collapse-item--active", move || is_show_content.get()),
move || class.get()
]>
<div
class="thaw-collapse-item__header"
on:click=on_click
>
<Icon icon=Icon::from(AiIcon::AiRightOutlined) class="thaw-collapse-item-arrow"/>
{move || title.get()}
</div>
<div
class="thaw-collapse-item__content"
style=move || (!is_show_content.get()).then_some("display: none;")
>
{children()}
</div>
</div>
}
}

33
thaw/src/collapse/mod.rs Normal file
View file

@ -0,0 +1,33 @@
mod collapse_item;
pub use collapse_item::CollapseItem;
use crate::utils::{class_list::class_list, mount_style};
use leptos::*;
use std::collections::HashSet;
#[component]
pub fn Collapse(
#[prop(optional, into)] class: MaybeSignal<String>,
#[prop(optional, into)] value: RwSignal<HashSet<String>>,
#[prop(optional)] accordion: bool,
children: Children,
) -> impl IntoView {
mount_style("collapser", include_str!("./collapse.css"));
view! {
<Provider value=CollapseInjection{ value, accordion }>
<div class=class_list!["thaw-collapse", move || class.get()]>{children()}</div>
</Provider>
}
}
#[derive(Clone)]
pub(crate) struct CollapseInjection {
pub value: RwSignal<HashSet<String>>,
pub accordion: bool,
}
pub(crate) fn use_collapse() -> CollapseInjection {
expect_context()
}

View file

@ -8,6 +8,7 @@ mod calendar;
mod card;
mod checkbox;
mod code;
mod collapse;
mod color_picker;
mod components;
mod date_picker;
@ -54,6 +55,7 @@ pub use card::*;
pub use checkbox::*;
pub use chrono;
pub use code::*;
pub use collapse::*;
pub use color_picker::*;
pub use date_picker::*;
pub use divider::*;