remove members by key

This commit is contained in:
Evan Carroll 2026-01-27 01:00:39 -06:00
parent ae210d5352
commit c945fb7c43
2 changed files with 49 additions and 23 deletions

View file

@ -663,13 +663,28 @@ pub fn Avatar(
// Effect to draw the avatar when canvas is ready or appearance changes
Effect::new(move |_| {
// Subscribe to redraw trigger so this effect re-runs when images load
let _ = redraw_trigger.get();
let trigger_count = redraw_trigger.get();
// Get current values from signals
let m = member.get();
let layout = layout_memo.get();
// Debug: log avatar redraw
web_sys::console::log_1(
&format!(
"[Avatar Redraw] user={} trigger={} pos=({:.1}, {:.1}) screen=({:.1}, {:.1})",
m.member.display_name,
trigger_count,
m.member.position_x,
m.member.position_y,
layout.canvas_screen_x,
layout.canvas_screen_y,
)
.into(),
);
let Some(canvas) = canvas_ref.get() else {
web_sys::console::log_1(&"[Avatar Redraw] canvas not ready".into());
return;
};
@ -716,7 +731,11 @@ pub fn Avatar(
// Set onload handler to trigger redraw when image loads
let trigger = set_redraw_trigger;
let path_for_log = normalized_path.clone();
let onload = Closure::once(Box::new(move || {
web_sys::console::log_1(
&format!("[Avatar] Image loaded: {}", path_for_log).into(),
);
trigger.update(|v| *v += 1);
}) as Box<dyn FnOnce()>);
img.set_onload(Some(onload.as_ref().unchecked_ref()));

View file

@ -468,14 +468,14 @@ pub fn RealmSceneViewer(
})
.into();
let members_by_key = Signal::derive(move || {
sorted_members.get().into_iter().enumerate()
.map(|(idx, m)| (member_key(&m), (idx, m)))
.collect::<HashMap<_, _>>()
});
let member_keys = Memo::new(move |_| {
sorted_members.get().iter().map(member_key).collect::<Vec<_>>()
// Create indexed members for z-ordering (index determines stacking)
let indexed_members = Signal::derive(move || {
sorted_members
.get()
.into_iter()
.enumerate()
.map(|(idx, m)| (idx, m))
.collect::<Vec<_>>()
});
let scene_name = scene.name.clone();
@ -511,33 +511,40 @@ pub fn RealmSceneViewer(
</div>
<div class="avatars-container absolute inset-0" style=format!("z-index: {}; pointer-events: none; overflow: visible;", Z_AVATARS_CONTAINER)>
<Show when=move || scales_ready.get() fallback=|| ()>
{move || {
member_keys.get().into_iter().map(|key| {
let member_signal = Signal::derive(move || {
members_by_key.get().get(&key).map(|(_, m)| m.clone()).expect("member key should exist")
<For
each=move || indexed_members.get()
key=|(_, m)| member_key(m)
children=move |(idx, initial_member)| {
let key = member_key(&initial_member);
let z_index = (idx as i32) + Z_AVATAR_BASE;
// Per-member Memo: only fires when THIS member's data changes
let member_memo: Memo<ChannelMemberWithAvatar> = Memo::new(move |_| {
sorted_members
.get()
.into_iter()
.find(|m| member_key(m) == key)
.unwrap_or_else(|| initial_member.clone())
});
let z_index_signal = Signal::derive(move || {
members_by_key.get().get(&key).map(|(idx, _)| (*idx as i32) + Z_AVATAR_BASE).unwrap_or(Z_AVATAR_BASE)
});
let z = z_index_signal.get_untracked();
// Derive bubble signal for this member
let bubble_signal = Signal::derive(move || {
// Bubble signal for this member
let bubble_signal: Signal<Option<ActiveBubble>> = Signal::derive(move || {
active_bubbles.get().get(&key).cloned()
});
view! {
<Avatar
member=member_signal
member=member_memo.into()
transform=scene_transform
prop_size=prop_size
z_index=z
z_index=z_index
text_em_size=text_em_size
screen_bounds=screen_bounds
active_bubble=bubble_signal
/>
}
}).collect_view()
}}
}
/>
{move || {
let Some(fading_signal) = fading_members else {
return Vec::new().into_iter().collect_view();