leptos_components/
badge.rs

1use components_core::{BASE_CLASS, concat};
2use leptos::prelude::*;
3use leptos::{IntoView, component, view};
4
5const LIMIT_NUMERIC: isize = 9;
6const LIMIT_NUMERIC_NEGATIVE: isize = -9;
7
8#[derive(Default, Debug, PartialEq)]
9pub enum Variant {
10    Completed,
11    Reading,
12    #[default]
13    Pending,
14    Unread,
15}
16
17impl Variant {
18    pub fn text(&self) -> &'static str {
19        match self {
20            Variant::Completed => "Completo",
21            Variant::Reading => "Leyendo",
22            Variant::Pending => "Pendiente",
23            Variant::Unread => "No leido",
24        }
25    }
26}
27
28#[derive(Default, Debug, PartialEq)]
29pub enum Type {
30    #[default]
31    Default,
32    Numeric,
33    Text,
34}
35
36#[component]
37pub fn Badge(
38    #[prop(into)] count: ReadSignal<isize>,
39    #[prop(into, optional)] variant: Variant,
40    #[prop(into, optional)] r#type: Type,
41) -> impl IntoView {
42    let class = crate::tw!(
43        concat!("text-paragraph-2 ", BASE_CLASS, "-badge"),
44        format!("{BASE_CLASS}-badge--variant-{variant:?}"),
45        format!("{BASE_CLASS}-badge--type-{type:?}"),
46    );
47
48    let display_value = move || match r#type {
49        Type::Default => count.get().to_string(),
50        Type::Numeric => {
51            let count = count.get();
52            match count {
53                ..=LIMIT_NUMERIC_NEGATIVE => LIMIT_NUMERIC_NEGATIVE.to_string(),
54                LIMIT_NUMERIC.. => format!("+{LIMIT_NUMERIC}"),
55                _ => count.to_string(),
56            }
57        }
58        Type::Text => variant.text().to_string(),
59    };
60
61    view! {
62        <div
63          class={class}
64        >
65          <div class={concat!(BASE_CLASS, "-badge__dot")} />
66          <span>{display_value}</span>
67        </div>
68    }
69}