feat: private messages.
This commit is contained in:
parent
0492043625
commit
22cc0fdc38
11 changed files with 1135 additions and 44 deletions
|
|
@ -44,6 +44,34 @@ fn parse_emote_command(cmd: &str) -> Option<String> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Parse a whisper command and return (target_name, message) if valid.
|
||||
///
|
||||
/// Supports `/w name message` and `/whisper name message`.
|
||||
#[cfg(feature = "hydrate")]
|
||||
fn parse_whisper_command(cmd: &str) -> Option<(String, String)> {
|
||||
let cmd = cmd.trim();
|
||||
|
||||
// Strip the leading slash if present
|
||||
let cmd = cmd.strip_prefix('/').unwrap_or(cmd);
|
||||
|
||||
// Check for `w <name> <message>` or `whisper <name> <message>`
|
||||
let rest = cmd
|
||||
.strip_prefix("whisper ")
|
||||
.or_else(|| cmd.strip_prefix("w "))
|
||||
.map(str::trim)?;
|
||||
|
||||
// Find the first space to separate name from message
|
||||
let space_idx = rest.find(' ')?;
|
||||
let name = rest[..space_idx].trim().to_string();
|
||||
let message = rest[space_idx + 1..].trim().to_string();
|
||||
|
||||
if name.is_empty() || message.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((name, message))
|
||||
}
|
||||
|
||||
/// Chat input component with emote command support.
|
||||
///
|
||||
/// Props:
|
||||
|
|
@ -205,12 +233,16 @@ pub fn ChatInput(
|
|||
let cmd = value[1..].to_lowercase();
|
||||
|
||||
// Show hint for slash commands (don't execute until Enter)
|
||||
// Match: /s[etting], /i[nventory], /w[hisper], or their full forms with args
|
||||
if cmd.is_empty()
|
||||
|| "setting".starts_with(&cmd)
|
||||
|| "inventory".starts_with(&cmd)
|
||||
|| "whisper".starts_with(&cmd)
|
||||
|| cmd == "setting"
|
||||
|| cmd == "settings"
|
||||
|| cmd == "inventory"
|
||||
|| cmd.starts_with("w ")
|
||||
|| cmd.starts_with("whisper ")
|
||||
{
|
||||
set_command_mode.set(CommandMode::ShowingSlashHint);
|
||||
} else {
|
||||
|
|
@ -317,9 +349,10 @@ pub fn ChatInput(
|
|||
if key == "Enter" {
|
||||
let msg = message.get();
|
||||
|
||||
// Handle slash commands - NEVER send as message
|
||||
// Handle slash commands
|
||||
if msg.starts_with('/') {
|
||||
let cmd = msg[1..].to_lowercase();
|
||||
|
||||
// /s, /se, /set, /sett, /setti, /settin, /setting, /settings
|
||||
if !cmd.is_empty() && ("setting".starts_with(&cmd) || cmd == "settings") {
|
||||
if let Some(ref callback) = on_open_settings {
|
||||
|
|
@ -331,9 +364,12 @@ pub fn ChatInput(
|
|||
input.set_value("");
|
||||
let _ = input.blur();
|
||||
}
|
||||
ev.prevent_default();
|
||||
return;
|
||||
}
|
||||
|
||||
// /i, /in, /inv, /inve, /inven, /invent, /invento, /inventor, /inventory
|
||||
else if !cmd.is_empty() && "inventory".starts_with(&cmd) {
|
||||
if !cmd.is_empty() && "inventory".starts_with(&cmd) {
|
||||
if let Some(ref callback) = on_open_inventory {
|
||||
callback.run(());
|
||||
}
|
||||
|
|
@ -343,7 +379,31 @@ pub fn ChatInput(
|
|||
input.set_value("");
|
||||
let _ = input.blur();
|
||||
}
|
||||
ev.prevent_default();
|
||||
return;
|
||||
}
|
||||
|
||||
// /w NAME message or /whisper NAME message
|
||||
if let Some((target_name, whisper_content)) = parse_whisper_command(&msg) {
|
||||
if !whisper_content.trim().is_empty() {
|
||||
ws_sender.with_value(|sender| {
|
||||
if let Some(send_fn) = sender {
|
||||
send_fn(ClientMessage::SendChatMessage {
|
||||
content: whisper_content.trim().to_string(),
|
||||
target_display_name: Some(target_name),
|
||||
});
|
||||
}
|
||||
});
|
||||
set_message.set(String::new());
|
||||
set_command_mode.set(CommandMode::None);
|
||||
if let Some(input) = input_ref.get() {
|
||||
input.set_value("");
|
||||
}
|
||||
}
|
||||
ev.prevent_default();
|
||||
return;
|
||||
}
|
||||
|
||||
// Invalid slash command - just ignore, don't send
|
||||
ev.prevent_default();
|
||||
return;
|
||||
|
|
@ -380,6 +440,7 @@ pub fn ChatInput(
|
|||
if let Some(send_fn) = sender {
|
||||
send_fn(ClientMessage::SendChatMessage {
|
||||
content: msg.trim().to_string(),
|
||||
target_display_name: None, // Broadcast to scene
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -440,7 +501,7 @@ pub fn ChatInput(
|
|||
</div>
|
||||
</Show>
|
||||
|
||||
// Slash command hint bar (/s[etting], /i[nventory])
|
||||
// Slash command hint bar (/s[etting], /i[nventory], /w[hisper])
|
||||
<Show when=move || command_mode.get() == CommandMode::ShowingSlashHint>
|
||||
<div class="absolute bottom-full left-0 mb-1 px-3 py-1 bg-gray-700/90 backdrop-blur-sm rounded text-sm">
|
||||
<span class="text-gray-400">"/"</span>
|
||||
|
|
@ -450,6 +511,10 @@ pub fn ChatInput(
|
|||
<span class="text-gray-400">"/"</span>
|
||||
<span class="text-blue-400">"i"</span>
|
||||
<span class="text-gray-500">"[nventory]"</span>
|
||||
<span class="text-gray-600 mx-2">"|"</span>
|
||||
<span class="text-gray-400">"/"</span>
|
||||
<span class="text-blue-400">"w"</span>
|
||||
<span class="text-gray-500">"[hisper] name"</span>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue