fix(ai): tighten empty chat cards
This commit is contained in:
parent
c0dada1a59
commit
dec0c94710
|
|
@ -2,7 +2,7 @@ use crate::theme::Theme;
|
|||
use crate::widgets::ai_chat_panel_controls::{
|
||||
attachment_row_hit, paint_attachment_row, ATTACHMENT_ROW_HEIGHT,
|
||||
};
|
||||
use crate::widgets::ai_chat_panel_paint::paint_examples;
|
||||
use crate::widgets::ai_chat_panel_paint::{example_card_rects, paint_examples};
|
||||
use crate::widgets::editor_state_ext::{theme_for, translate};
|
||||
use crate::widgets::icons::{draw_icon, Icon};
|
||||
use crate::widgets::{LayoutBox, LayoutCx, PaintCx, Widget, WidgetId};
|
||||
|
|
@ -373,20 +373,8 @@ impl<'a> AIChatPlaceholder<'a> {
|
|||
}
|
||||
if self.state.messages.is_empty() {
|
||||
// Examples grid hit-test (only rendered when no messages).
|
||||
let card_w = (rect.size.x - PAD * 2.0 - 8.0) / 2.0;
|
||||
let card_h = 70.0;
|
||||
let grid_y = rect.origin.y + HEADER_HEIGHT + 32.0;
|
||||
for (i, ex) in self.examples.iter().enumerate() {
|
||||
let col = (i % 2) as f32;
|
||||
let row = (i / 2) as f32;
|
||||
let card = Rect {
|
||||
origin: Point2D::new(
|
||||
rect.origin.x + PAD + col * (card_w + 8.0),
|
||||
grid_y + row * (card_h + 8.0),
|
||||
),
|
||||
size: Point2D::new(card_w, card_h),
|
||||
};
|
||||
if rect_contains(card, point) {
|
||||
for (card, ex) in example_card_rects(rect).iter().zip(self.examples.iter()) {
|
||||
if rect_contains(*card, point) {
|
||||
return Some(AIChatHit::Example(ex.prompt.clone()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,21 @@ fn hit_test_resolves_first_example_when_empty() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hit_test_keeps_quick_action_card_height_compact() {
|
||||
let s = EditorState::new();
|
||||
let panel = AIChatPlaceholder::from_editor(&s);
|
||||
let rect = Rect::xywh(0.0, 0.0, AI_CHAT_WIDTH, AI_CHAT_HEIGHT);
|
||||
let card_w = (AI_CHAT_WIDTH - PAD * 2.0 - 8.0) / 2.0;
|
||||
let compact_card_h = 58.0;
|
||||
let p = Point2D::new(
|
||||
PAD + card_w / 2.0,
|
||||
HEADER_HEIGHT + 32.0 + compact_card_h + 4.0,
|
||||
);
|
||||
|
||||
assert_eq!(panel.hit_test(rect, p), Some(AIChatHit::DragHandle));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hit_test_header_returns_drag_handle() {
|
||||
let s = EditorState::new();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,31 @@
|
|||
use super::ai_chat_panel::{to_jian_color, ExampleCard, HEADER_HEIGHT, PAD};
|
||||
use crate::theme::Theme;
|
||||
use crate::widgets::PaintCx;
|
||||
use crate::{Point2D, Rect, TextLayout};
|
||||
use crate::{Color, Point2D, Rect, TextLayout};
|
||||
|
||||
pub(crate) const EXAMPLE_CARD_GAP: f32 = 8.0;
|
||||
pub(crate) const EXAMPLE_CARD_HEIGHT: f32 = 58.0;
|
||||
const EXAMPLE_CARD_PAD: f32 = 12.0;
|
||||
|
||||
pub(crate) fn example_card_rects(rect: Rect) -> [Rect; 4] {
|
||||
let grid_y = rect.origin.y + HEADER_HEIGHT + 32.0;
|
||||
let card_w = (rect.size.x - PAD * 2.0 - EXAMPLE_CARD_GAP) / 2.0;
|
||||
std::array::from_fn(|i| {
|
||||
let col = (i % 2) as f32;
|
||||
let row = (i / 2) as f32;
|
||||
Rect {
|
||||
origin: Point2D::new(
|
||||
rect.origin.x + PAD + col * (card_w + EXAMPLE_CARD_GAP),
|
||||
grid_y + row * (EXAMPLE_CARD_HEIGHT + EXAMPLE_CARD_GAP),
|
||||
),
|
||||
size: Point2D::new(card_w, EXAMPLE_CARD_HEIGHT),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn with_alpha(color: Color, a: f32) -> Color {
|
||||
Color { a, ..color }
|
||||
}
|
||||
|
||||
/// Paint the empty-state hint line + the 2×2 example-card grid.
|
||||
pub(crate) fn paint_examples(
|
||||
|
|
@ -25,26 +49,16 @@ pub(crate) fn paint_examples(
|
|||
Point2D::new(0.0, 0.0),
|
||||
);
|
||||
let hint_y = rect.origin.y + HEADER_HEIGHT + 16.0;
|
||||
let hint_w = cx.backend.measure_text(hint_label, 12.0);
|
||||
cx.backend.draw_text(
|
||||
&hint,
|
||||
Point2D::new(rect.origin.x + rect.size.x / 2.0 - 40.0, hint_y),
|
||||
Point2D::new(rect.origin.x + (rect.size.x - hint_w) / 2.0, hint_y),
|
||||
);
|
||||
|
||||
let grid_origin_y = hint_y + 16.0;
|
||||
let card_w = (rect.size.x - PAD * 2.0 - 8.0) / 2.0;
|
||||
let card_h = 70.0;
|
||||
for (i, ex) in examples.iter().enumerate() {
|
||||
let col = (i % 2) as f32;
|
||||
let row = (i / 2) as f32;
|
||||
let card = Rect {
|
||||
origin: Point2D::new(
|
||||
rect.origin.x + PAD + col * (card_w + 8.0),
|
||||
grid_origin_y + row * (card_h + 8.0),
|
||||
),
|
||||
size: Point2D::new(card_w, card_h),
|
||||
};
|
||||
cx.backend.fill_round_rect(card, 8.0, theme.muted);
|
||||
cx.backend.stroke_round_rect(card, 8.0, theme.border, 1.0);
|
||||
let card_bg = with_alpha(theme.muted, 0.3);
|
||||
for (card, ex) in example_card_rects(rect).iter().zip(examples.iter()) {
|
||||
cx.backend.fill_round_rect(*card, 8.0, card_bg);
|
||||
cx.backend.stroke_round_rect(*card, 8.0, theme.border, 1.0);
|
||||
let emoji_layout = TextLayout::single_run(
|
||||
ex.emoji,
|
||||
"system-ui",
|
||||
|
|
@ -54,7 +68,10 @@ pub(crate) fn paint_examples(
|
|||
);
|
||||
cx.backend.draw_text(
|
||||
&emoji_layout,
|
||||
Point2D::new(card.origin.x + 12.0, card.origin.y + 22.0),
|
||||
Point2D::new(
|
||||
card.origin.x + EXAMPLE_CARD_PAD,
|
||||
card.origin.y + EXAMPLE_CARD_PAD + 10.0,
|
||||
),
|
||||
);
|
||||
let title_layout = TextLayout::single_run(
|
||||
&ex.title,
|
||||
|
|
@ -65,7 +82,10 @@ pub(crate) fn paint_examples(
|
|||
);
|
||||
cx.backend.draw_text(
|
||||
&title_layout,
|
||||
Point2D::new(card.origin.x + 36.0, card.origin.y + 22.0),
|
||||
Point2D::new(
|
||||
card.origin.x + EXAMPLE_CARD_PAD + 20.0,
|
||||
card.origin.y + EXAMPLE_CARD_PAD + 10.0,
|
||||
),
|
||||
);
|
||||
let subtitle_layout = TextLayout::single_run(
|
||||
&ex.subtitle,
|
||||
|
|
@ -76,14 +96,17 @@ pub(crate) fn paint_examples(
|
|||
);
|
||||
cx.backend.draw_text(
|
||||
&subtitle_layout,
|
||||
Point2D::new(card.origin.x + 36.0, card.origin.y + 42.0),
|
||||
Point2D::new(
|
||||
card.origin.x + EXAMPLE_CARD_PAD,
|
||||
card.origin.y + EXAMPLE_CARD_PAD + 28.0,
|
||||
),
|
||||
);
|
||||
}
|
||||
let tip = TextLayout::single_run(
|
||||
tip_label,
|
||||
"system-ui",
|
||||
10.0,
|
||||
to_jian_color(theme.muted_foreground),
|
||||
to_jian_color(with_alpha(theme.muted_foreground, 0.5)),
|
||||
Point2D::new(0.0, 0.0),
|
||||
);
|
||||
let tip_w = cx.backend.measure_text(tip_label, 10.0);
|
||||
|
|
@ -91,7 +114,12 @@ pub(crate) fn paint_examples(
|
|||
&tip,
|
||||
Point2D::new(
|
||||
rect.origin.x + (rect.size.x - tip_w) / 2.0,
|
||||
grid_origin_y + card_h * 2.0 + 8.0 * 2.0 + 22.0,
|
||||
rect.origin.y
|
||||
+ HEADER_HEIGHT
|
||||
+ 32.0
|
||||
+ EXAMPLE_CARD_HEIGHT * 2.0
|
||||
+ EXAMPLE_CARD_GAP * 2.0
|
||||
+ 22.0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue