make emotions named instead, add drop prop

This commit is contained in:
Evan Carroll 2026-01-13 16:49:07 -06:00
parent 989e20757b
commit ea3b444d71
19 changed files with 1429 additions and 150 deletions

View file

@ -34,10 +34,10 @@ enum CommandMode {
ShowingList,
}
/// Parse an emote command and return the emotion index if valid.
/// Parse an emote command and return the emotion name if valid.
///
/// Supports `:e name`, `:emote name` with partial matching.
fn parse_emote_command(cmd: &str) -> Option<u8> {
fn parse_emote_command(cmd: &str) -> Option<String> {
let cmd = cmd.trim().to_lowercase();
// Strip the leading colon if present
@ -52,9 +52,8 @@ fn parse_emote_command(cmd: &str) -> Option<u8> {
name.and_then(|n| {
EMOTIONS
.iter()
.enumerate()
.find(|(_, ename)| ename.starts_with(n) || n.starts_with(**ename))
.map(|(idx, _)| idx as u8)
.find(|ename| ename.starts_with(n) || n.starts_with(**ename))
.map(|ename| (*ename).to_string())
})
}
@ -97,12 +96,10 @@ pub fn ChatInput(
// Apply emotion via WebSocket
let apply_emotion = {
move |emotion_idx: u8| {
move |emotion: String| {
ws_sender.with_value(|sender| {
if let Some(send_fn) = sender {
send_fn(ClientMessage::UpdateEmotion {
emotion: emotion_idx,
});
send_fn(ClientMessage::UpdateEmotion { emotion });
}
});
// Clear input and close popup
@ -199,8 +196,8 @@ pub fn ChatInput(
};
// Popup select handler
let on_popup_select = Callback::new(move |emotion_idx: u8| {
apply_emotion(emotion_idx);
let on_popup_select = Callback::new(move |emotion: String| {
apply_emotion(emotion);
});
let on_popup_close = Callback::new(move |_: ()| {
@ -265,10 +262,11 @@ pub fn ChatInput(
fn EmoteListPopup(
emotion_availability: Signal<Option<EmotionAvailability>>,
skin_preview_path: Signal<Option<String>>,
on_select: Callback<u8>,
on_close: Callback<()>,
on_select: Callback<String>,
#[prop(into)] on_close: Callback<()>,
) -> impl IntoView {
// Get list of available emotions
let _ = on_close; // Suppress unused warning
// Get list of available emotions (name, preview_path)
let available_emotions = move || {
emotion_availability
.get()
@ -279,7 +277,7 @@ fn EmoteListPopup(
.filter(|(idx, _)| avail.available.get(*idx).copied().unwrap_or(false))
.map(|(idx, name)| {
let preview = avail.preview_paths.get(idx).cloned().flatten();
(idx as u8, *name, preview)
((*name).to_string(), preview)
})
.collect::<Vec<_>>()
})
@ -296,24 +294,26 @@ fn EmoteListPopup(
<div class="grid grid-cols-3 gap-1 max-h-64 overflow-y-auto">
<For
each=move || available_emotions()
key=|(idx, _, _): &(u8, &str, Option<String>)| *idx
children=move |(emotion_idx, emotion_name, preview_path): (u8, &str, Option<String>)| {
key=|(name, _): &(String, Option<String>)| name.clone()
children=move |(emotion_name, preview_path): (String, Option<String>)| {
let on_select = on_select.clone();
let skin_path = skin_preview_path.get();
let emotion_name_for_click = emotion_name.clone();
let _skin_path = skin_preview_path.get();
let _emotion_path = preview_path.clone();
view! {
<button
type="button"
class="flex items-center gap-2 p-2 rounded hover:bg-gray-700 transition-colors text-left w-full"
on:click=move |_| on_select.run(emotion_idx)
on:click=move |_| on_select.run(emotion_name_for_click.clone())
role="option"
>
<EmotionPreview
skin_path=skin_path.clone()
emotion_path=preview_path.clone()
skin_path=_skin_path.clone()
emotion_path=_emotion_path.clone()
/>
<span class="text-white text-sm">
":e "
{emotion_name}
{emotion_name.clone()}
</span>
</button>
}