avatar fixes and implementation to edit

This commit is contained in:
Evan Carroll 2026-01-17 01:11:05 -06:00
parent acab2f017d
commit c3320ddcce
11 changed files with 1417 additions and 37 deletions

View file

@ -12,9 +12,9 @@ use leptos_router::hooks::use_params_map;
use uuid::Uuid;
use crate::components::{
ActiveBubble, Card, ChatInput, ChatMessage, EmotionKeybindings, InventoryPopup,
KeybindingsPopup, MessageLog, RealmHeader, RealmSceneViewer, SettingsPopup, ViewerSettings,
DEFAULT_BUBBLE_TIMEOUT_MS,
ActiveBubble, AvatarEditorPopup, Card, ChatInput, ChatMessage, EmotionKeybindings,
InventoryPopup, KeybindingsPopup, MessageLog, RealmHeader, RealmSceneViewer, SettingsPopup,
ViewerSettings, DEFAULT_BUBBLE_TIMEOUT_MS,
};
#[cfg(feature = "hydrate")]
use crate::components::use_channel_websocket;
@ -105,6 +105,11 @@ pub fn RealmPage() -> impl IntoView {
let keybindings = RwSignal::new(EmotionKeybindings::load());
let (keybindings_open, set_keybindings_open) = signal(false);
// Avatar editor popup state
let (avatar_editor_open, set_avatar_editor_open) = signal(false);
// Store full avatar data for the editor
let (full_avatar, set_full_avatar) = signal(Option::<AvatarWithPaths>::None);
// Scene dimensions (extracted from bounds_wkt when scene loads)
let (scene_dimensions, set_scene_dimensions) = signal((800.0_f64, 600.0_f64));
@ -193,6 +198,8 @@ pub fn RealmPage() -> impl IntoView {
set_emotion_availability.set(Some(avail));
// Get skin layer position 4 (center) for preview
set_skin_preview_path.set(avatar.skin_layer[4].clone());
// Store full avatar for the editor
set_full_avatar.set(Some(avatar));
}
}
}
@ -462,6 +469,13 @@ pub fn RealmPage() -> impl IntoView {
return;
}
// Handle 'a' to toggle avatar editor
if key == "a" || key == "A" {
set_avatar_editor_open.update(|v| *v = !*v);
ev.prevent_default();
return;
}
// Check if 'e' key was pressed
if key == "e" || key == "E" {
*e_pressed_clone.borrow_mut() = true;
@ -732,6 +746,31 @@ pub fn RealmPage() -> impl IntoView {
skin_preview_path=Signal::derive(move || skin_preview_path.get())
on_close=Callback::new(move |_: ()| set_keybindings_open.set(false))
/>
// Avatar editor popup
{
#[cfg(feature = "hydrate")]
let ws_sender_for_avatar = ws_sender.clone();
#[cfg(not(feature = "hydrate"))]
let ws_sender_for_avatar: StoredValue<Option<WsSender>, LocalStorage> = StoredValue::new_local(None);
view! {
<AvatarEditorPopup
open=Signal::derive(move || avatar_editor_open.get())
on_close=Callback::new(move |_: ()| set_avatar_editor_open.set(false))
avatar=Signal::derive(move || full_avatar.get())
realm_slug=Signal::derive(move || slug.get())
on_avatar_update=Callback::new(move |updated: AvatarWithPaths| {
set_full_avatar.set(Some(updated.clone()));
// Update emotion availability for the emotion picker
let avail = updated.compute_emotion_availability();
set_emotion_availability.set(Some(avail));
// Update skin preview
set_skin_preview_path.set(updated.skin_layer[4].clone());
})
ws_sender=ws_sender_for_avatar
/>
}
}
}
.into_any()
}