use leptos::prelude::*;
use leptos::tachys::view::any_view::IntoAny;
use orbital_macros::component_doc;
use turf::inline_style_sheet_values;
use crate::components::{
AvatarColor, Caption1, Card, CardContent, Flex, FlexAlign, FlexGap, FlexWrap, Link, Persona,
PersonaConfig, PersonaPrimaryText, PersonaSecondaryText, PersonaSize, Subtitle1,
};
fn map_avatar_size(px: u8) -> PersonaSize {
match px {
0..=22 => PersonaSize::ExtraSmall,
23..=27 => PersonaSize::Small,
28..=33 => PersonaSize::Medium,
34..=37 => PersonaSize::Large,
38..=47 => PersonaSize::ExtraLarge,
_ => PersonaSize::Huge,
}
}
#[component_doc(
category = "Data Display",
preview_slug = "components/patterns/identity-card",
preview_label = "Identity Card",
preview_icon = icondata::AiIdcardOutlined,
)]
#[component]
pub fn IdentityCard(
#[prop(optional, into)]
name: MaybeProp<String>,
#[prop(into)]
title: MaybeProp<String>,
#[prop(optional, into)]
subtitle: MaybeProp<String>,
#[prop(optional, into)]
email: MaybeProp<String>,
#[prop(optional, into)]
handle: MaybeProp<String>,
#[prop(optional, into)]
avatar_size: MaybeProp<u8>,
#[prop(optional, into)]
color: MaybeProp<AvatarColor>,
#[prop(optional, default = false)]
embedded: bool,
) -> impl IntoView {
let (style_sheet, class_names) = inline_style_sheet_values! {
.Card {
width: 100%;
max-width: 100%;
margin: 0;
box-sizing: border-box;
border: 1px solid var(--orb-color-border-default);
border-radius: 10px;
background: var(--orb-color-surface-canvas-hover);
}
.Content {
--orbital-card-content-padding: 12px;
}
.Muted {
color: var(--orb-color-text-tertiary);
}
};
view! {
<style>{style_sheet}</style>
{move || {
let persona = move || {
let avatar_px = avatar_size.get().unwrap_or(40);
let persona_config = PersonaConfig {
name: name.get(),
size: map_avatar_size(avatar_px),
color: color.get().unwrap_or(AvatarColor::Colorful),
..Default::default()
};
let title_text = title.get().unwrap_or_default();
if let Some(sub) = subtitle.get() {
view! {
<Persona config=persona_config>
<PersonaPrimaryText slot>
<Subtitle1>{title_text.clone()}</Subtitle1>
</PersonaPrimaryText>
<PersonaSecondaryText slot>{sub}</PersonaSecondaryText>
</Persona>
}
.into_any()
} else {
view! {
<Persona config=persona_config>
<PersonaPrimaryText slot>
<Subtitle1>{title_text}</Subtitle1>
</PersonaPrimaryText>
</Persona>
}
.into_any()
}
};
let contact = move || {
let email_val = email.get();
let handle_val = handle.get();
if email_val.is_none() && handle_val.is_none() {
return None;
}
Some(view! {
<Flex gap=FlexGap::Small wrap=FlexWrap::Wrap align=FlexAlign::Center>
{email_val.map(|e| {
let href = format!("mailto:{e}");
view! {
<Link href=href inline=true>{e}</Link>
}
})}
{handle_val.map(|h| view! {
<Caption1 class=class_names.muted>{h}</Caption1>
})}
</Flex>
})
};
if embedded {
view! {
<Flex vertical=true gap=FlexGap::Small align=FlexAlign::Stretch>
{persona()}
{contact()}
</Flex>
}
.into_any()
} else {
view! {
<Card class=class_names.card>
<CardContent class=class_names.content>
<Flex vertical=true gap=FlexGap::Small align=FlexAlign::Stretch>
{persona()}
{contact()}
</Flex>
</CardContent>
</Card>
}
.into_any()
}
}}
}
}