mirror of
https://github.com/ZSeven-W/openpencil.git
synced 2026-06-01 03:14:29 +07:00
style(panels): align top-bar glyphs + smaller icons + left dividers
Match the TS top bar and the user's refinement feedback: - icons 16→14px, chevron 12→10px (top-bar-local consts; other widgets keep their own sizes) — a touch smaller / more refined; - route every glyph through `glyph_top(center_y, size)` and center the agent chip's icon + 11px text on the shared center line (fixes the off-axis drift); - add a divider between the sidebar toggle and the file-menu (user request) and unify all three dividers via `paint_divider` (1×14, border@60%, 4px gaps) — TS `w-px h-3.5 bg-border/60 mx-1`; - keep paint + hit-test in sync for the new divider spans.
This commit is contained in:
parent
0f2e751088
commit
21f98dff61
1 changed files with 68 additions and 30 deletions
|
|
@ -13,7 +13,10 @@ use crate::{Color, Point2D, Rect, TextLayout};
|
|||
use op_editor_core::editor_ui_state::EditorUiState;
|
||||
|
||||
pub const TOP_BAR_HEIGHT: f32 = 40.0;
|
||||
const ICON_SIZE: f32 = 16.0;
|
||||
// Top-bar glyph size — 14 px (a touch smaller than the old 16 and
|
||||
// matching the TS `size-[15px]` chrome). Local to the top bar; other
|
||||
// widgets keep their own `ICON_SIZE`.
|
||||
const ICON_SIZE: f32 = 14.0;
|
||||
const ICON_BUTTON: f32 = 28.0;
|
||||
/// Globe locale-picker button — wider than a normal icon button so a
|
||||
/// chevron-down sits next to the globe glyph (signals the dropdown).
|
||||
|
|
@ -22,8 +25,13 @@ const GLOBE_BUTTON_WIDTH: f32 = 44.0;
|
|||
/// inside a single round-rect background. Tighter gap than two
|
||||
/// separate icon buttons (4 px between glyphs vs ICON_BUTTON + 4).
|
||||
const FILE_MENU_BUTTON_WIDTH: f32 = 46.0;
|
||||
const CHEVRON_SIZE: f32 = 12.0;
|
||||
const CHEVRON_SIZE: f32 = 10.0;
|
||||
const PAD: f32 = 12.0;
|
||||
/// Top-bar vertical divider geometry (TS `w-px h-3.5 bg-border/60
|
||||
/// mx-1`): 1 px wide, 14 px tall, 4 px gap on each side.
|
||||
const DIVIDER_W: f32 = 1.0;
|
||||
const DIVIDER_H: f32 = 14.0;
|
||||
const DIVIDER_GAP: f32 = 4.0;
|
||||
/// Gap between the stacked per-agent brand icons in the chip.
|
||||
const AGENT_ICON_GAP: f32 = 4.0;
|
||||
/// Diameter of a macOS-style window-control dot.
|
||||
|
|
@ -301,7 +309,10 @@ impl TopBar {
|
|||
if rect_contains(panel_left_rect, point) {
|
||||
return Some(TopBarHit::ToggleSidebar);
|
||||
}
|
||||
let file_menu_x = rect.origin.x + PAD + self.left_inset() + ICON_BUTTON + 4.0;
|
||||
// Mirror the paint layout: panel │ file-menu │ Figma, each
|
||||
// group split by a divider (DIVIDER_GAP + DIVIDER_W + DIVIDER_GAP).
|
||||
let divider_span = DIVIDER_GAP + DIVIDER_W + DIVIDER_GAP;
|
||||
let file_menu_x = rect.origin.x + PAD + self.left_inset() + ICON_BUTTON + divider_span;
|
||||
let file_menu_rect = Rect {
|
||||
origin: Point2D::new(file_menu_x, icon_y),
|
||||
size: Point2D::new(FILE_MENU_BUTTON_WIDTH, ICON_BUTTON),
|
||||
|
|
@ -309,7 +320,7 @@ impl TopBar {
|
|||
if rect_contains(file_menu_rect, point) {
|
||||
return Some(TopBarHit::ToggleFileMenu);
|
||||
}
|
||||
let figma_x = file_menu_x + FILE_MENU_BUTTON_WIDTH + 13.0;
|
||||
let figma_x = file_menu_x + FILE_MENU_BUTTON_WIDTH + divider_span;
|
||||
let figma_rect = Rect {
|
||||
origin: Point2D::new(figma_x, icon_y),
|
||||
size: Point2D::new(ICON_BUTTON, ICON_BUTTON),
|
||||
|
|
@ -354,7 +365,10 @@ impl TopBar {
|
|||
let approx_text_w = chip_chars as f32 * 12.0;
|
||||
let chip_w = 8.0 + self.agent_icons_width() + 6.0 + dot_w + approx_text_w + 12.0 + 16.0;
|
||||
let chip_rect = Rect {
|
||||
origin: Point2D::new(globe.origin.x - chip_w - 6.0, rect.origin.y + 4.0),
|
||||
origin: Point2D::new(
|
||||
globe.origin.x - chip_w - (DIVIDER_GAP * 2.0 + DIVIDER_W),
|
||||
rect.origin.y + 4.0,
|
||||
),
|
||||
size: Point2D::new(chip_w, rect.size.y - 8.0),
|
||||
};
|
||||
if rect_contains(chip_rect, point) {
|
||||
|
|
@ -490,22 +504,21 @@ impl Widget for TopBar {
|
|||
}
|
||||
}
|
||||
// ── Left cluster ───────────────────────────────────────
|
||||
// sidebar toggle │ file-menu │ Figma — each group split by a
|
||||
// TS-style 1×14 divider (4 px gap each side).
|
||||
let panel_left_x = rect.origin.x + PAD + self.left_inset();
|
||||
paint_icon_button(cx, &self.theme, panel_left_x, center_y, Icon::PanelLeft);
|
||||
// Divider between the sidebar toggle and the file-menu.
|
||||
let divider1_x = panel_left_x + ICON_BUTTON + DIVIDER_GAP;
|
||||
paint_divider(cx, &self.theme, divider1_x, center_y);
|
||||
// File-menu compound: folder + tight chevron in one button.
|
||||
let file_menu_x = panel_left_x + ICON_BUTTON + 4.0;
|
||||
let file_menu_x = divider1_x + DIVIDER_W + DIVIDER_GAP;
|
||||
paint_file_menu_button(cx, &self.theme, file_menu_x, center_y);
|
||||
// Vertical divider before the Figma import affordance.
|
||||
let divider_x = file_menu_x + FILE_MENU_BUTTON_WIDTH + 6.0;
|
||||
cx.backend.fill_rect(
|
||||
Rect {
|
||||
origin: Point2D::new(divider_x, center_y - 8.0),
|
||||
size: Point2D::new(1.0, 16.0),
|
||||
},
|
||||
self.theme.border,
|
||||
);
|
||||
// Divider before the Figma import affordance.
|
||||
let divider2_x = file_menu_x + FILE_MENU_BUTTON_WIDTH + DIVIDER_GAP;
|
||||
paint_divider(cx, &self.theme, divider2_x, center_y);
|
||||
// Figma import button.
|
||||
let figma_x = divider_x + 6.0;
|
||||
let figma_x = divider2_x + DIVIDER_W + DIVIDER_GAP;
|
||||
paint_figma_button(cx, &self.theme, figma_x, center_y);
|
||||
|
||||
// ── Centered file name ─────────────────────────────────
|
||||
|
|
@ -587,8 +600,12 @@ impl Widget for TopBar {
|
|||
let icons_w = self.agent_icons_width();
|
||||
let text_w = cx.backend.measure_text(chip_text, 11.0);
|
||||
let chip_w = 8.0 + icons_w + 6.0 + dot_w + text_w + 12.0;
|
||||
// Leave room for the chip↔globe divider (4 px gap + 1 px + 4 px).
|
||||
let chip_rect = Rect {
|
||||
origin: Point2D::new(rx - chip_w - 6.0, center_y - 13.0),
|
||||
origin: Point2D::new(
|
||||
rx - chip_w - (DIVIDER_GAP * 2.0 + DIVIDER_W),
|
||||
center_y - 13.0,
|
||||
),
|
||||
size: Point2D::new(chip_w, 26.0),
|
||||
};
|
||||
// Leading icons (no border ring — TS empty-state chip has no
|
||||
|
|
@ -596,14 +613,14 @@ impl Widget for TopBar {
|
|||
// set-up affordance; the active chip stacks one brand logo
|
||||
// per connected provider so the user sees *which* agents
|
||||
// are on.
|
||||
let icons_y = chip_rect.origin.y + 4.0;
|
||||
let icons_y = glyph_top(center_y, ICON_SIZE);
|
||||
if self.agent_count == 0 {
|
||||
draw_icon(
|
||||
cx.backend,
|
||||
Icon::LayoutGrid,
|
||||
Point2D::new(chip_rect.origin.x + 8.0, icons_y),
|
||||
ICON_SIZE,
|
||||
self.theme.foreground,
|
||||
self.theme.muted_foreground,
|
||||
1.4,
|
||||
);
|
||||
} else {
|
||||
|
|
@ -648,19 +665,17 @@ impl Widget for TopBar {
|
|||
to_jian_color(self.theme.muted_foreground),
|
||||
Point2D::new(0.0, 0.0),
|
||||
);
|
||||
// 11 px text centred on the bar's center line (ascent ≈ 8 px).
|
||||
cx.backend
|
||||
.draw_text(&chip_label, Point2D::new(text_x, chip_rect.origin.y + 18.0));
|
||||
.draw_text(&chip_label, Point2D::new(text_x, center_y + 4.0));
|
||||
|
||||
// Vertical divider between the agent chip and the globe button
|
||||
// (TS: `w-px h-3.5 bg-border/60`) — groups the status chip
|
||||
// apart from the locale/theme/fullscreen controls.
|
||||
let divider_x = globe_button.origin.x - 3.0;
|
||||
cx.backend.fill_rect(
|
||||
Rect {
|
||||
origin: Point2D::new(divider_x, center_y - 7.0),
|
||||
size: Point2D::new(1.0, 14.0),
|
||||
},
|
||||
self.theme.border,
|
||||
// Divider between the agent chip and the globe button — groups
|
||||
// the status chip apart from the locale/theme/fullscreen controls.
|
||||
paint_divider(
|
||||
cx,
|
||||
&self.theme,
|
||||
globe_button.origin.x - DIVIDER_GAP - DIVIDER_W,
|
||||
center_y,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -720,6 +735,29 @@ fn paint_figma_button(cx: &mut PaintCx<'_>, theme: &Theme, x: f32, center_y: f32
|
|||
);
|
||||
}
|
||||
|
||||
/// Top-left y for a glyph of `size` vertically centred on `center_y`.
|
||||
/// Every top-bar glyph routes through this so the whole bar shares
|
||||
/// one center line.
|
||||
fn glyph_top(center_y: f32, size: f32) -> f32 {
|
||||
center_y - size / 2.0
|
||||
}
|
||||
|
||||
/// Paint a top-bar vertical divider with its left edge at `x`,
|
||||
/// centred on `center_y` (TS `w-px h-3.5 bg-border/60`).
|
||||
fn paint_divider(cx: &mut PaintCx<'_>, theme: &Theme, x: f32, center_y: f32) {
|
||||
let color = Color {
|
||||
a: theme.border.a * 0.6,
|
||||
..theme.border
|
||||
};
|
||||
cx.backend.fill_rect(
|
||||
Rect {
|
||||
origin: Point2D::new(x, center_y - DIVIDER_H / 2.0),
|
||||
size: Point2D::new(DIVIDER_W, DIVIDER_H),
|
||||
},
|
||||
color,
|
||||
);
|
||||
}
|
||||
|
||||
fn to_jian_color(c: Color) -> jian_core::scene::Color {
|
||||
fn ch(v: f32) -> u8 {
|
||||
(v.clamp(0.0, 1.0) * 255.0).round() as u8
|
||||
|
|
|
|||
Loading…
Reference in a new issue