use vizia_storage::LayoutChildIterator;
use crate::prelude::*;
#[derive(Debug, Default, Clone, Copy, PartialEq)]
pub enum AvatarVariant {
#[default]
Circle,
Square,
Rounded,
}
pub struct Avatar {}
impl Avatar {
pub fn new<F>(cx: &mut Context, content: F) -> Handle<Self>
where
F: FnOnce(&mut Context),
{
Self {}.build(cx, content).variant(AvatarVariant::Circle).control_size(ControlSize::Medium)
}
}
impl View for Avatar {
fn element(&self) -> Option<&'static str> {
Some("avatar")
}
}
pub trait AvatarModifiers: Sized {
fn variant<U: Into<AvatarVariant> + Clone + PartialEq + 'static>(
self,
variant: impl Res<U> + 'static,
) -> Self;
#[allow(unused_variables)]
fn badge<F>(self, content: F) -> Self
where
F: FnOnce(&mut Context) -> Handle<'_, Badge>,
{
self
}
}
impl AvatarModifiers for Handle<'_, Avatar> {
fn variant<U: Into<AvatarVariant> + Clone + PartialEq + 'static>(
mut self,
variant: impl Res<U> + 'static,
) -> Self {
let avatar_variant = variant.to_signal(self.context()).map(|value| value.clone().into());
let is_circle = Memo::new(move |_| avatar_variant.get() == AvatarVariant::Circle);
let is_square = Memo::new(move |_| avatar_variant.get() == AvatarVariant::Square);
let is_rounded = Memo::new(move |_| avatar_variant.get() == AvatarVariant::Rounded);
self.toggle_class("circle", is_circle)
.toggle_class("square", is_square)
.toggle_class("rounded", is_rounded)
}
fn badge<F>(mut self, content: F) -> Self
where
F: FnOnce(&mut Context) -> Handle<'_, Badge>,
{
let entity = self.entity();
self.context().with_current(entity, |cx| {
(content)(cx);
});
self
}
}
impl ControlModifiers for Handle<'_, Avatar> {
fn control_size<U: Into<ControlSize> + Clone + 'static>(
self,
size: impl Res<U> + 'static,
) -> Self {
crate::modifiers::bind_control_size(self, size)
}
}
pub struct AvatarGroup {}
impl AvatarGroup {
pub fn new<F>(cx: &mut Context, content: F) -> Handle<Self>
where
F: FnOnce(&mut Context),
{
Self {}.build(cx, content)
}
}
fn apply_avatar_group_max_visible(cx: &mut Context, entity: Entity, max_visible: usize) {
let mut avatars = Vec::new();
let mut overflow_avatar = None;
for child in LayoutChildIterator::new(&cx.tree, entity) {
let is_overflow = cx
.style
.classes
.get(child)
.is_some_and(|class_list| class_list.contains("avatar-group-overflow"));
if is_overflow {
overflow_avatar = Some(child);
} else {
avatars.push(child);
}
}
if let Some(overflow_avatar) = overflow_avatar {
cx.remove(overflow_avatar);
}
let hidden_count = avatars.len().saturating_sub(max_visible);
for (index, avatar) in avatars.into_iter().enumerate() {
let display = if index < max_visible { Display::Flex } else { Display::None };
Handle::<Avatar> { current: entity, entity: avatar, p: Default::default(), cx }
.display(display);
}
if hidden_count > 0 {
cx.with_current(entity, |cx| {
Avatar::new(cx, move |cx| {
Label::new(cx, format!("+{}", hidden_count));
})
.class("avatar-group-overflow");
});
}
}
impl View for AvatarGroup {
fn element(&self) -> Option<&'static str> {
Some("avatar-group")
}
}
impl AvatarModifiers for Handle<'_, AvatarGroup> {
fn variant<U: Into<AvatarVariant> + Clone + PartialEq + 'static>(
mut self,
variant: impl Res<U> + 'static,
) -> Self {
let avatar_variant = variant.to_signal(self.context()).map(|value| value.clone().into());
let is_circle = Memo::new(move |_| avatar_variant.get() == AvatarVariant::Circle);
let is_square = Memo::new(move |_| avatar_variant.get() == AvatarVariant::Square);
let is_rounded = Memo::new(move |_| avatar_variant.get() == AvatarVariant::Rounded);
self.toggle_class("circle", is_circle)
.toggle_class("square", is_square)
.toggle_class("rounded", is_rounded)
}
}
impl ControlModifiers for Handle<'_, AvatarGroup> {
fn control_size<U: Into<ControlSize> + Clone + 'static>(
self,
size: impl Res<U> + 'static,
) -> Self {
crate::modifiers::bind_control_size(self, size)
}
}
impl Handle<'_, AvatarGroup> {
pub fn max_visible(self, max_visible: impl Res<usize> + 'static) -> Self {
let max_visible = max_visible.to_signal(self.cx);
self.bind(max_visible, move |mut handle| {
let max_visible = max_visible.get();
let entity = handle.entity();
apply_avatar_group_max_visible(handle.context(), entity, max_visible);
})
}
}