refactor(editor): sink remaining icon buttons to jian IconButton

The AI-chat header (New Chat / maximize), component-browser header
(close + export/import kit), icon-picker close, and figma-import close
buttons now render through jian IconButton instead of hand-rolled
paint_ghost_button_feedback + draw_icon. Drops the now-orphaned
paint_header_btn_bg helper; host hit-tests are unchanged.
This commit is contained in:
Kayshen-X 2026-06-20 13:28:41 +08:00
parent dc67272bad
commit d64fc3c344
4 changed files with 79 additions and 99 deletions

View file

@ -405,39 +405,42 @@ impl<'a> Widget for AIChatPlaceholder<'a> {
&title,
Point2D::new(rect.origin.x + PAD + 28.0, header_y + 14.0),
);
let tokens = crate::widgets::button::tokens_from_theme(&self.theme);
let maximize_x = rect.origin.x + rect.size.x - PAD - 50.0;
let maximize_color = paint_header_btn_bg(
cx,
&self.theme,
maximize_x,
header_y,
self.header_hover == Some(ChatHeaderButton::ToggleMaximize),
self.header_pressed == Some(ChatHeaderButton::ToggleMaximize),
);
draw_icon(
jian_widgets::components::icon_button::IconButton {
icon_paths: self.maximize_icon().paths(),
hovered: self.header_hover == Some(ChatHeaderButton::ToggleMaximize),
pressed: self.header_pressed == Some(ChatHeaderButton::ToggleMaximize),
active: false,
enabled: true,
icon_size: 18.0,
stroke_width: 1.4,
}
.paint(
cx.backend,
self.maximize_icon(),
Point2D::new(maximize_x, header_y),
18.0,
maximize_color,
1.4,
Rect {
origin: Point2D::new(maximize_x, header_y),
size: Point2D::new(22.0, 22.0),
},
&tokens,
);
let new_chat_x = rect.origin.x + rect.size.x - PAD - 22.0;
let new_chat_color = paint_header_btn_bg(
cx,
&self.theme,
new_chat_x,
header_y,
self.header_hover == Some(ChatHeaderButton::NewChat),
self.header_pressed == Some(ChatHeaderButton::NewChat),
);
draw_icon(
jian_widgets::components::icon_button::IconButton {
icon_paths: Icon::Plus.paths(),
hovered: self.header_hover == Some(ChatHeaderButton::NewChat),
pressed: self.header_pressed == Some(ChatHeaderButton::NewChat),
active: false,
enabled: true,
icon_size: 18.0,
stroke_width: 1.4,
}
.paint(
cx.backend,
Icon::Plus,
Point2D::new(new_chat_x, header_y),
18.0,
new_chat_color,
1.4,
Rect {
origin: Point2D::new(new_chat_x, header_y),
size: Point2D::new(22.0, 22.0),
},
&tokens,
);
// Body — either messages or examples.
@ -786,26 +789,6 @@ fn chat_neutral_feedback_color(theme: &Theme, pressed: bool) -> Color {
}
}
/// Paint the `theme.button_hover` wash behind a bare header glyph
/// (18 px, drawn at `(icon_x, header_y)`) when the cursor rests on it,
/// returning the glyph color: foreground while hovered, muted
/// otherwise. The wash is a 24 px square centred on the glyph.
fn paint_header_btn_bg(
cx: &mut PaintCx<'_>,
theme: &Theme,
icon_x: f32,
header_y: f32,
hovered: bool,
pressed: bool,
) -> Color {
let center = Point2D::new(icon_x + 9.0, header_y + 9.0);
let r = Rect {
origin: Point2D::new(center.x - 12.0, center.y - 12.0),
size: Point2D::new(24.0, 24.0),
};
crate::widgets::button::paint_ghost_button_feedback(cx.backend, theme, r, hovered, pressed)
}
#[cfg(test)]
#[path = "ai_chat_panel/tests.rs"]
mod tests;

View file

@ -8,7 +8,7 @@
//! click to a [`ComponentBrowserHit`], and owns the drag + insert.
use crate::theme::Theme;
use crate::widgets::button::{paint_button_feedback_wash, paint_ghost_button_feedback};
use crate::widgets::button::paint_button_feedback_wash;
use crate::widgets::editor_state_ext::theme_for;
use crate::widgets::{draw_icon, Icon, PaintCx};
use crate::{Color, Point2D, Rect, TextLayout};
@ -425,20 +425,19 @@ impl<'a> ComponentBrowserPanel<'a> {
cx.backend.fill_round_rect(close, 6.0, self.theme.muted);
let close_hovered = self.hover == Some(ComponentBrowserButton::Close);
let close_pressed = self.is_pressed(ComponentBrowserButton::Close);
let close_color = paint_ghost_button_feedback(
jian_widgets::components::icon_button::IconButton {
icon_paths: Icon::Close.paths(),
hovered: close_hovered,
pressed: close_pressed,
active: false,
enabled: true,
icon_size: CLOSE_BTN - 10.0,
stroke_width: 1.5,
}
.paint(
cx.backend,
&self.theme,
close,
close_hovered,
close_pressed,
);
draw_icon(
cx.backend,
Icon::Close,
Point2D::new(close.origin.x + 5.0, close.origin.y + 5.0),
CLOSE_BTN - 10.0,
close_color,
1.5,
&crate::widgets::button::tokens_from_theme(&self.theme),
);
// Header kit actions — Download (export) + Upload (import),
// TS `component-browser-panel.tsx` header buttons.
@ -456,15 +455,19 @@ impl<'a> ComponentBrowserPanel<'a> {
] {
let hovered = self.hover == Some(hover_target);
let pressed = self.is_pressed(hover_target);
let icon_color =
paint_ghost_button_feedback(cx.backend, &self.theme, btn, hovered, pressed);
draw_icon(
jian_widgets::components::icon_button::IconButton {
icon_paths: icon.paths(),
hovered,
pressed,
active: false,
enabled: true,
icon_size: CLOSE_BTN - 10.0,
stroke_width: 1.5,
}
.paint(
cx.backend,
icon,
Point2D::new(btn.origin.x + 5.0, btn.origin.y + 5.0),
CLOSE_BTN - 10.0,
icon_color,
1.5,
btn,
&crate::widgets::button::tokens_from_theme(&self.theme),
);
}
cx.backend.fill_rect(

View file

@ -7,7 +7,7 @@
use crate::theme::Theme;
use crate::widgets::editor_state_ext::theme_for;
use crate::widgets::icons::{draw_icon, Icon};
use crate::widgets::icons::Icon;
use crate::widgets::{LayoutBox, LayoutCx, PaintCx, Widget, WidgetId};
use crate::{Point2D, Rect, TextLayout};
use op_editor_core::editor_ui_state::Locale;
@ -145,24 +145,19 @@ impl Widget for FigmaImportModal {
origin: Point2D::new(close.origin.x - pad, close.origin.y - pad),
size: Point2D::new(close.size.x + pad * 2.0, close.size.y + pad * 2.0),
};
crate::widgets::button::paint_ghost_button_feedback(
jian_widgets::components::icon_button::IconButton {
icon_paths: Icon::Close.paths(),
hovered: close_hovered,
pressed: close_pressed,
active: false,
enabled: true,
icon_size: close.size.x,
stroke_width: 1.6,
}
.paint(
cx.backend,
&self.theme,
bg,
close_hovered,
close_pressed,
);
draw_icon(
cx.backend,
Icon::Close,
close.origin,
close.size.x,
if close_hovered || close_pressed {
self.theme.foreground
} else {
self.theme.muted_foreground
},
1.6,
&crate::widgets::button::tokens_from_theme(&self.theme),
);
// Compact info panel with a small Figma glyph for character.

View file

@ -1,7 +1,7 @@
//! Native Iconify picker used by the toolbar and icon property row.
use crate::theme::Theme;
use crate::widgets::button::{paint_button_feedback_wash, paint_ghost_button_feedback};
use crate::widgets::button::paint_button_feedback_wash;
use crate::widgets::editor_state_ext::theme_for;
use crate::widgets::icon_catalog::{search_icons, IconCatalogEntry, IconRenderStyle};
use crate::widgets::{
@ -248,20 +248,19 @@ impl<'a> IconPickerPanel<'a> {
let close = Self::close_rect(panel);
let close_hovered = self.hover == Some(ICON_PICKER_CLOSE_HOVER);
let close_pressed = self.pressed == Some(ICON_PICKER_CLOSE_HOVER);
let icon_color = paint_ghost_button_feedback(
jian_widgets::components::icon_button::IconButton {
icon_paths: Icon::Close.paths(),
hovered: close_hovered,
pressed: close_pressed,
active: false,
enabled: true,
icon_size: 14.0,
stroke_width: 1.4,
}
.paint(
cx.backend,
&self.theme,
close,
close_hovered,
close_pressed,
);
draw_icon(
cx.backend,
Icon::Close,
Point2D::new(close.origin.x + 5.0, close.origin.y + 5.0),
14.0,
icon_color,
1.4,
&crate::widgets::button::tokens_from_theme(&self.theme),
);
}