use leptos::{either::Either, prelude::*};
use orbital_base_components::AvatarColor;
use orbital_macros::component_doc;
use orbital_style::inject_style;
use super::styles::persona_styles;
use super::types::{
PersonaConfig, PersonaPrimaryText, PersonaQuaternaryText, PersonaSecondaryText,
PersonaTertiaryText, PersonaTextAlignment, PersonaTextPosition,
};
use crate::{Avatar, AvatarConfig, Flex, FlexAlign, FlexGap, Stack, StackConfig};
#[component_doc(
category = "Data Display",
preview_slug = "persona",
preview_label = "Persona",
preview_icon = icondata::AiIdcardOutlined,
)]
#[component]
pub fn Persona(
#[prop(optional, into)]
class: MaybeProp<String>,
#[prop(optional, into)]
style: MaybeProp<String>,
#[prop(optional, into)]
config: PersonaConfig,
#[prop(optional)]
persona_primary_text: Option<PersonaPrimaryText>,
#[prop(optional)]
persona_secondary_text: Option<PersonaSecondaryText>,
#[prop(optional)]
persona_tertiary_text: Option<PersonaTertiaryText>,
#[prop(optional)]
persona_quaternary_text: Option<PersonaQuaternaryText>,
) -> impl IntoView {
inject_style("orbital-persona", persona_styles());
let name = StoredValue::new(config.name.clone());
let avatar_src = StoredValue::new(config.avatar_src.clone());
let avatar_color = StoredValue::new(config.color);
let size = StoredValue::new(config.size);
let text_alignment = StoredValue::new(config.text_alignment);
let text_position = StoredValue::new(config.text_position);
let avatar_gap = config.size.avatar_gap();
let avatar_size = Memo::new(move |_| size.with_value(|size| size.as_avatar_size()));
let is_before = config.text_position == PersonaTextPosition::Before;
let is_below = config.text_position == PersonaTextPosition::Below;
let avatar_first = !is_before;
let flex_align = if is_below {
FlexAlign::Center
} else {
match config.text_alignment {
PersonaTextAlignment::Start => FlexAlign::Start,
PersonaTextAlignment::Center => FlexAlign::Center,
}
};
let outer_style = move || {
let mut s = String::new();
style.with(|style| {
if let Some(style) = style.as_ref() {
s.push_str(style);
}
});
s
};
view! {
<div
class=move || {
let mut parts = vec![
"orbital-persona".to_string(),
format!(
"orbital-persona--{}",
text_alignment.with_value(|alignment| alignment.as_str())
),
format!(
"orbital-persona--{}",
text_position.with_value(|position| position.as_str())
),
format!(
"orbital-persona--{}",
size.with_value(|size| size.as_str())
),
];
if let Some(extra) = class.get() {
if !extra.is_empty() {
parts.push(extra);
}
}
parts.join(" ")
}
style=outer_style
>
<Flex inline=true vertical=is_below gap=avatar_gap align=flex_align>
<Show when=move || avatar_first>
<PersonaAvatar
name
avatar_src
avatar_color
avatar_size
/>
</Show>
<PersonaTextStack
name
persona_primary_text
persona_secondary_text
persona_tertiary_text
persona_quaternary_text
/>
<Show when=move || is_before>
<PersonaAvatar
name
avatar_src
avatar_color
avatar_size
/>
</Show>
</Flex>
</div>
}
}
#[component]
fn PersonaAvatar(
name: StoredValue<Option<String>>,
avatar_src: StoredValue<Option<String>>,
avatar_color: StoredValue<AvatarColor>,
avatar_size: Memo<u8>,
) -> impl IntoView {
view! {
<Avatar
class="orbital-persona__avatar".to_string()
config=AvatarConfig {
name: name.with_value(|name| name.clone()),
src: avatar_src.with_value(|src| src.clone()),
size: Some(avatar_size.get()),
color: avatar_color.with_value(|color| *color),
..Default::default()
}
/>
}
}
#[component]
fn PersonaTextStack(
name: StoredValue<Option<String>>,
persona_primary_text: Option<PersonaPrimaryText>,
persona_secondary_text: Option<PersonaSecondaryText>,
persona_tertiary_text: Option<PersonaTertiaryText>,
persona_quaternary_text: Option<PersonaQuaternaryText>,
) -> impl IntoView {
view! {
<Stack
config=StackConfig::vertical(FlexGap::Size(0))
class="orbital-persona__text".to_string()
>
{if let Some(text) = persona_primary_text {
Either::Left(
view! { <span class="orbital-persona__primary-text">{(text.children)()}</span> },
)
} else {
Either::Right(move || {
if let Some(name) = name.with_value(|name| name.clone()) {
Either::Left(
view! { <span class="orbital-persona__primary-text">{name}</span> },
)
} else {
Either::Right(())
}
})
}}
{if let Some(text) = persona_secondary_text {
Either::Left(
view! { <span class="orbital-persona__secondary-text">{(text.children)()}</span> },
)
} else {
Either::Right(())
}}
{if let Some(text) = persona_tertiary_text {
Either::Left(
view! { <span class="orbital-persona__tertiary-text">{(text.children)()}</span> },
)
} else {
Either::Right(())
}}
{if let Some(text) = persona_quaternary_text {
Either::Left(
view! { <span class="orbital-persona__quaternary-text">{(text.children)()}</span> },
)
} else {
Either::Right(())
}}
</Stack>
}
}