Skip to content

Commit

Permalink
feat: Adds Persona component (#386)
Browse files Browse the repository at this point in the history
  • Loading branch information
luoxiaozero authored Mar 2, 2025
1 parent 8110a9a commit 7a0b31f
Show file tree
Hide file tree
Showing 8 changed files with 502 additions and 0 deletions.
1 change: 1 addition & 0 deletions demo/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ fn TheRouter() -> impl IntoView {
<Route path=path!("/message-bar") view=MessageBarMdPage />
<Route path=path!("/nav") view=NavMdPage />
<Route path=path!("/pagination") view=PaginationMdPage />
<Route path=path!("/persona") view=PersonaMdPage />
<Route path=path!("/popover") view=PopoverMdPage />
<Route path=path!("/progress-bar") view=ProgressBarMdPage />
<Route path=path!("/radio") view=RadioMdPage />
Expand Down
5 changes: 5 additions & 0 deletions demo/src/pages/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,11 @@ pub(crate) fn gen_nav_data() -> Vec<NavGroupOption> {
value: "/components/pagination",
label: "Pagination",
},
NavItemOption {
group: None,
value: "/components/persona",
label: "Persona",
},
NavItemOption {
group: None,
value: "/components/popover",
Expand Down
1 change: 1 addition & 0 deletions demo_markdown/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt
"MessageBarMdPage" => "../../thaw/src/message_bar/docs/mod.md",
"NavMdPage" => "../../thaw/src/nav/docs/mod.md",
"PaginationMdPage" => "../../thaw/src/pagination/docs/mod.md",
"PersonaMdPage" => "../../thaw/src/persona/docs/mod.md",
"PopoverMdPage" => "../../thaw/src/popover/docs/mod.md",
"ProgressBarMdPage" => "../../thaw/src/progress_bar/docs/mod.md",
"RadioMdPage" => "../../thaw/src/radio/docs/mod.md",
Expand Down
2 changes: 2 additions & 0 deletions thaw/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ mod menu;
mod message_bar;
mod nav;
mod pagination;
mod persona;
mod popover;
mod progress_bar;
mod radio;
Expand Down Expand Up @@ -92,6 +93,7 @@ pub use menu::*;
pub use message_bar::*;
pub use nav::*;
pub use pagination::*;
pub use persona::*;
pub use popover::*;
pub use progress_bar::*;
pub use radio::*;
Expand Down
168 changes: 168 additions & 0 deletions thaw/src/persona/docs/mod.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Persona

```rust demo
view! {
<Persona
name="Thaw"
avatar_src="https://s3.bmp.ovh/imgs/2021/10/723d457d627fe706.jpg"
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
</Persona>
}
```

### Text Alignment

A Persona supports two text alignments, `start` being the default position.

```rust demo
view! {
<Flex justify=FlexJustify::SpaceAround>
<Persona
name="Thaw UI"
text_alignment=PersonaTextAlignment::Start
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
<PersonaTertiaryText slot>
"Card"
</PersonaTertiaryText>
<PersonaQuaternaryText slot>
"Header"
</PersonaQuaternaryText>
</Persona>
<Persona
name="Thaw UI"
text_alignment=PersonaTextAlignment::Center
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
<PersonaTertiaryText slot>
"Card"
</PersonaTertiaryText>
<PersonaQuaternaryText slot>
"Header"
</PersonaQuaternaryText>
</Persona>
</Flex>
}
```

### Text Position

A Persona supports three text positions, `after` being the default position.

```rust demo
view! {
<Flex justify=FlexJustify::SpaceAround>
<Persona
name="Thaw"
text_position=PersonaTextPosition::After
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
</Persona>
<Persona
name="Thaw"
text_position=PersonaTextPosition::Below
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
</Persona>
<Persona
name="Thaw"
text_position=PersonaTextPosition::Before
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
</Persona>
</Flex>
}
```

### Avatar Size

A Persona supports different sizes, medium being the default.

```rust demo
view! {
<Flex>
<Persona
name="Thaw"
size=PersonaSize::ExtraSmall
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
</Persona>
<Persona
name="Thaw"
size=PersonaSize::Small
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
</Persona>
<Persona
name="Thaw"
size=PersonaSize::Medium
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
</Persona>
<Persona
name="Thaw"
size=PersonaSize::Large
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
</Persona>
<Persona
name="Thaw"
size=PersonaSize::ExtraLarge
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
</Persona>
<Persona
name="Thaw"
size=PersonaSize::Huge
>
<PersonaSecondaryText slot>
"UI"
</PersonaSecondaryText>
</Persona>
</Flex>
}
```

### Persona Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| class | `MaybeProp<String>` | `Default::default()` | |
| style | `MaybeProp<String>` | `Default::default()` | |
| name | `MaybeProp<String>` | `None` | The name of the person or entity represented by the Persona. |
| size | `Signal<PersonaSize>` | `PersonaSize::Medium` | The size of a Persona and its text. |
| text_alignment | `Signal<PersonaTextAlignment>` | `PersonaTextAlignment::Start` | The vertical alignment of the text relative to the avatar. |
| text_position | `Signal<PersonaTextPosition>` | `PersonaTextPosition::After` | The position of the text relative to the avatar. |
| persona_primary_text | slot `Option<PersonaPrimaryText>` | `None` | The first line of text in the Persona, larger than the rest of the lines. |
| persona_secondary_text | slot `Option<PersonaSecondaryText>` | `None` | The second line of text in the Persona. |
| persona_tertiary_text | slot `Option<PersonaTertiaryText>` | `None` | The third line of text in the Persona. |
| persona_quaternary_text | slot `Option<PersonaQuaternaryText>` | `None` | The fourth line of text in the Persona. |

### PersonaPrimaryText & PersonaSecondaryText & PersonaTertiaryText & PersonaQuaternaryText Props

| Name | Type | Default | Description |
| -------- | ---------- | ------- | ----------- |
| children | `Children` | | |
139 changes: 139 additions & 0 deletions thaw/src/persona/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
mod types;

pub use types::*;

use crate::Avatar;
use leptos::{either::Either, prelude::*};
use thaw_components::{If, Then};
use thaw_utils::{class_list, mount_style};

#[component]
pub fn Persona(
#[prop(optional, into)] class: MaybeProp<String>,
#[prop(optional, into)] style: MaybeProp<String>,
/// The name of the person or entity represented by the Persona.
/// When primary_text is not provided, this will be used as the default value for primaryText.
#[prop(optional, into)]
name: MaybeProp<String>,
/// The size of a Persona and its text.
#[prop(optional, into)]
size: Signal<PersonaSize>,
/// The vertical alignment of the text relative to the avatar.
#[prop(optional, into)]
text_alignment: Signal<PersonaTextAlignment>,
/// The position of the text relative to the avatar.
#[prop(optional, into)]
text_position: Signal<PersonaTextPosition>,
#[prop(optional, into)] avatar_src: MaybeProp<String>,
/// The first line of text in the Persona, larger than the rest of the lines.
#[prop(optional)]
persona_primary_text: Option<PersonaPrimaryText>,
/// The second line of text in the Persona.
#[prop(optional)]
persona_secondary_text: Option<PersonaSecondaryText>,
/// The third line of text in the Persona.
#[prop(optional)]
persona_tertiary_text: Option<PersonaTertiaryText>,
/// The fourth line of text in the Persona.
#[prop(optional)]
persona_quaternary_text: Option<PersonaQuaternaryText>,
) -> impl IntoView {
mount_style("persona", include_str!("./persona.css"));

let text_position_before =
Memo::new(move |_| text_position.get() == PersonaTextPosition::Before);

let style = move || {
let css_var = match size.get() {
PersonaSize::ExtraSmall => "spacingHorizontalSNudge",
PersonaSize::Small => "spacingHorizontalS",
PersonaSize::Medium => "spacingHorizontalS",
PersonaSize::Large => "spacingHorizontalMNudge",
PersonaSize::ExtraLarge => "spacingHorizontalMNudge",
PersonaSize::Huge => "spacingHorizontalM",
};

let mut s = format!("--thaw-persona__avatar-spacing: var(--{css_var});");

style.with(|style| {
if let Some(style) = style.as_ref() {
s.push_str(style);
}
});

s
};

let avatar_size = Memo::new(move |_| size.get().as_avatar_size());

view! {
<div
class=class_list![
"thaw-persona",
move || format!("thaw-persona--{}", text_alignment.get().as_str()),
move || format!("thaw-persona--{}", text_position.get().as_str()),
move || format!("thaw-persona--{}", size.get().as_str()),
class
]
style=style
>
<If cond=Signal::derive(move || !text_position_before.get())>
<Then slot>
<Avatar
class="thaw-persona__avatar"
name=name
src=avatar_src
size=avatar_size
/>
</Then>
</If>
{if let Some(text) = persona_primary_text {
Either::Left(
view! { <span class="thaw-persona__primary-text">{(text.children)()}</span> },
)
} else {
Either::Right(move || {
if let Some(name) = name.get() {
Either::Left(
view! { <span class="thaw-persona__primary-text">{name}</span> },
)
} else {
Either::Right(())
}
})
}}
{if let Some(text) = persona_secondary_text {
Either::Left(
view! { <span class="thaw-persona__secondary-text">{(text.children)()}</span> },
)
} else {
Either::Right(())
}}
{if let Some(text) = persona_tertiary_text {
Either::Left(
view! { <span class="thaw-persona__tertiary-text">{(text.children)()}</span> },
)
} else {
Either::Right(())
}}
{if let Some(text) = persona_quaternary_text {
Either::Left(
view! { <span class="thaw-persona__quaternary-text">{(text.children)()}</span> },
)
} else {
Either::Right(())
}}

<If cond=text_position_before>
<Then slot>
<Avatar
class="thaw-persona__avatar"
name=name
src=avatar_src
size=avatar_size
/>
</Then>
</If>
</div>
}
}
Loading

0 comments on commit 7a0b31f

Please sign in to comment.