feat: private messages.
This commit is contained in:
parent
0492043625
commit
22cc0fdc38
11 changed files with 1135 additions and 44 deletions
|
|
@ -81,6 +81,11 @@ impl ContentBounds {
|
|||
fn empty_bottom_rows(&self) -> usize {
|
||||
2 - self.max_row
|
||||
}
|
||||
|
||||
/// Number of empty rows at the top (for bubble positioning).
|
||||
fn empty_top_rows(&self) -> usize {
|
||||
self.min_row
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a unique key for a member (for Leptos For keying).
|
||||
|
|
@ -386,7 +391,17 @@ pub fn AvatarCanvas(
|
|||
if let Some(ref b) = bubble {
|
||||
let current_time = js_sys::Date::now() as i64;
|
||||
if b.expires_at >= current_time {
|
||||
draw_bubble(&ctx, b, avatar_cx, avatar_cy - avatar_size / 2.0, avatar_size, te);
|
||||
let content_x_offset = content_bounds.x_offset(cell_size);
|
||||
let content_top_adjustment = content_bounds.empty_top_rows() as f64 * cell_size;
|
||||
draw_bubble(
|
||||
&ctx,
|
||||
b,
|
||||
avatar_cx,
|
||||
avatar_cy - avatar_size / 2.0,
|
||||
content_x_offset,
|
||||
content_top_adjustment,
|
||||
te,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -426,7 +441,8 @@ fn draw_bubble(
|
|||
bubble: &ActiveBubble,
|
||||
center_x: f64,
|
||||
top_y: f64,
|
||||
_prop_size: f64,
|
||||
content_x_offset: f64,
|
||||
content_top_adjustment: f64,
|
||||
text_em_size: f64,
|
||||
) {
|
||||
// Text scale independent of zoom - only affected by user's text_em_size setting
|
||||
|
|
@ -440,8 +456,11 @@ fn draw_bubble(
|
|||
|
||||
let (bg_color, border_color, text_color) = emotion_bubble_colors(&bubble.message.emotion);
|
||||
|
||||
// Use italic font for whispers
|
||||
let font_style = if bubble.message.is_whisper { "italic " } else { "" };
|
||||
|
||||
// Measure and wrap text
|
||||
ctx.set_font(&format!("{}px sans-serif", font_size));
|
||||
ctx.set_font(&format!("{}{}px sans-serif", font_style, font_size));
|
||||
let lines = wrap_text(ctx, &bubble.message.content, max_bubble_width - padding * 2.0);
|
||||
|
||||
// Calculate bubble dimensions
|
||||
|
|
@ -453,9 +472,13 @@ fn draw_bubble(
|
|||
let bubble_width = bubble_width.max(60.0 * text_scale);
|
||||
let bubble_height = (lines.len() as f64) * line_height + padding * 2.0;
|
||||
|
||||
// Position bubble above avatar
|
||||
let bubble_x = center_x - bubble_width / 2.0;
|
||||
let bubble_y = top_y - bubble_height - tail_size - 5.0 * text_scale;
|
||||
// Center bubble horizontally on content (not grid center)
|
||||
let content_center_x = center_x + content_x_offset;
|
||||
let bubble_x = content_center_x - bubble_width / 2.0;
|
||||
|
||||
// Position vertically closer to content when top rows are empty
|
||||
let adjusted_top_y = top_y + content_top_adjustment;
|
||||
let bubble_y = adjusted_top_y - bubble_height - tail_size - 5.0 * text_scale;
|
||||
|
||||
// Draw bubble background
|
||||
draw_rounded_rect(ctx, bubble_x, bubble_y, bubble_width, bubble_height, border_radius);
|
||||
|
|
@ -465,18 +488,19 @@ fn draw_bubble(
|
|||
ctx.set_line_width(2.0);
|
||||
ctx.stroke();
|
||||
|
||||
// Draw tail
|
||||
// Draw tail pointing to content center
|
||||
ctx.begin_path();
|
||||
ctx.move_to(center_x - tail_size, bubble_y + bubble_height);
|
||||
ctx.line_to(center_x, bubble_y + bubble_height + tail_size);
|
||||
ctx.line_to(center_x + tail_size, bubble_y + bubble_height);
|
||||
ctx.move_to(content_center_x - tail_size, bubble_y + bubble_height);
|
||||
ctx.line_to(content_center_x, bubble_y + bubble_height + tail_size);
|
||||
ctx.line_to(content_center_x + tail_size, bubble_y + bubble_height);
|
||||
ctx.close_path();
|
||||
ctx.set_fill_style_str(bg_color);
|
||||
ctx.fill();
|
||||
ctx.set_stroke_style_str(border_color);
|
||||
ctx.stroke();
|
||||
|
||||
// Draw text
|
||||
// Draw text (re-set font in case canvas state changed)
|
||||
ctx.set_font(&format!("{}{}px sans-serif", font_style, font_size));
|
||||
ctx.set_fill_style_str(text_color);
|
||||
ctx.set_text_align("left");
|
||||
ctx.set_text_baseline("top");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue