mirror of
https://github.com/ZSeven-W/openpencil.git
synced 2026-05-31 19:04:29 +07:00
feat(panels): add git-panel button to the top bar
The top bar had no affordance to open the git panel (only a keyboard/menu path). Add a TS-style git button just right of the file name: a `GitBranch` glyph + the current branch name when in a repo. Always shown (per request) — a click toggles the git panel, which offers `init` when the doc isn't yet a repo. - new `Icon::GitBranch` lucide glyph; - `TopBar.git_branch` from `git_panel.branch`; `git_button_rect` (CJK-aware width estimate so it clears a CJK file name) shared by paint + hit-test; `TopBarHit::ToggleGitPanel`; - native host mirrors `main.rs` toggle bookkeeping (per-frame refresh does the scan); web host toggles `git_panel.open`.
This commit is contained in:
parent
e2f0e4e1a0
commit
a4b70fa055
6 changed files with 110 additions and 0 deletions
|
|
@ -74,6 +74,8 @@ pub enum Icon {
|
|||
PanelLeft,
|
||||
/// FolderOpen — TopBar folder.
|
||||
FolderOpen,
|
||||
/// GitBranch — TopBar git-panel toggle next to the file name.
|
||||
GitBranch,
|
||||
/// Sparkles — agent active indicator.
|
||||
Sparkles,
|
||||
/// X — close affordance.
|
||||
|
|
@ -257,6 +259,7 @@ impl Icon {
|
|||
Icon::Hash => HASH,
|
||||
Icon::PanelLeft => PANEL_LEFT,
|
||||
Icon::FolderOpen => FOLDER_OPEN,
|
||||
Icon::GitBranch => GIT_BRANCH,
|
||||
Icon::Sparkles => SPARKLES,
|
||||
Icon::Close => CLOSE,
|
||||
Icon::Trash => TRASH,
|
||||
|
|
@ -402,6 +405,7 @@ impl Icon {
|
|||
"download" => Icon::Download,
|
||||
"file-text" => Icon::FileText,
|
||||
"folder-open" | "folder" => Icon::FolderOpen,
|
||||
"git-branch" | "git" => Icon::GitBranch,
|
||||
"sparkles" => Icon::Sparkles,
|
||||
"diamond" => Icon::Diamond,
|
||||
"component" => Icon::Component,
|
||||
|
|
|
|||
|
|
@ -122,6 +122,14 @@ pub(super) const FOLDER_OPEN: &[&str] = &[
|
|||
"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",
|
||||
];
|
||||
|
||||
pub(super) const GIT_BRANCH: &[&str] = &[
|
||||
// lucide git-branch: line + two r=3 circles + connecting arc.
|
||||
"M6 3v12",
|
||||
"M18 6 m-3 0 a3 3 0 1 0 6 0 a3 3 0 1 0 -6 0",
|
||||
"M6 18 m-3 0 a3 3 0 1 0 6 0 a3 3 0 1 0 -6 0",
|
||||
"M18 9a9 9 0 0 1-9 9",
|
||||
];
|
||||
|
||||
pub(super) const SPARKLES: &[&str] = &[
|
||||
"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",
|
||||
"M20 2v4",
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ fn every_variant_paints_at_least_one_primitive() {
|
|||
Icon::Hash,
|
||||
Icon::PanelLeft,
|
||||
Icon::FolderOpen,
|
||||
Icon::GitBranch,
|
||||
Icon::Sparkles,
|
||||
Icon::Close,
|
||||
Icon::ChevronUp,
|
||||
|
|
|
|||
|
|
@ -79,6 +79,8 @@ pub enum TopBarHit {
|
|||
ToggleLocale,
|
||||
/// Agents and MCP chip — open the agent settings modal.
|
||||
OpenAgentSettings,
|
||||
/// Git-branch button next to the file name — toggle the git panel.
|
||||
ToggleGitPanel,
|
||||
}
|
||||
|
||||
pub struct TopBar {
|
||||
|
|
@ -108,6 +110,10 @@ pub struct TopBar {
|
|||
/// Dark mode (click to go light), a Moon glyph in Light mode
|
||||
/// (click to go dark).
|
||||
pub theme_mode: op_editor_core::ThemeMode,
|
||||
/// Current git branch when the open document is in a repo — shown
|
||||
/// beside the file name. `None` = no branch (the button still
|
||||
/// paints, icon-only, as a toggle for the git panel).
|
||||
pub git_branch: Option<String>,
|
||||
}
|
||||
|
||||
impl TopBar {
|
||||
|
|
@ -125,6 +131,7 @@ impl TopBar {
|
|||
traffic_hover: false,
|
||||
fullscreen: false,
|
||||
theme_mode: op_editor_core::ThemeMode::Dark,
|
||||
git_branch: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,6 +168,7 @@ impl TopBar {
|
|||
traffic_hover: ui.topbar_traffic_hover,
|
||||
fullscreen: ui.window_fullscreen,
|
||||
theme_mode: ui.theme_mode,
|
||||
git_branch: ui.git_panel.branch.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,6 +271,34 @@ impl TopBar {
|
|||
}
|
||||
}
|
||||
|
||||
/// Git-panel toggle button — sits just right of the centred file
|
||||
/// name. Width holds the branch glyph plus an optional branch
|
||||
/// label. Shared by paint + hit-test so they can't drift.
|
||||
fn git_button_rect(&self, top_bar_rect: Rect) -> Rect {
|
||||
let center_y = top_bar_rect.origin.y + top_bar_rect.size.y / 2.0;
|
||||
// The name is *centred* using the 9 px/char heuristic, but a
|
||||
// CJK glyph renders ~14 px wide, so the real right edge is
|
||||
// further out — use a CJK-aware estimate so the button clears
|
||||
// the (often CJK) file name instead of overlapping it.
|
||||
let center_approx = self.file_name.chars().count() as f32 * 9.0;
|
||||
let render_w: f32 = self
|
||||
.file_name
|
||||
.chars()
|
||||
.map(|c| if is_wide_glyph(c) { 14.0 } else { 7.5 })
|
||||
.sum();
|
||||
let filename_left = top_bar_rect.origin.x + (top_bar_rect.size.x - center_approx) / 2.0;
|
||||
let filename_right = filename_left + render_w;
|
||||
let branch_w = self
|
||||
.git_branch
|
||||
.as_deref()
|
||||
.map(|b| 6.0 + b.chars().count() as f32 * 7.0)
|
||||
.unwrap_or(0.0);
|
||||
Rect {
|
||||
origin: Point2D::new(filename_right + 10.0, center_y - ICON_BUTTON / 2.0),
|
||||
size: Point2D::new(ICON_SIZE + 8.0 + branch_w, ICON_BUTTON),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve a press on the left-edge window-control dots.
|
||||
/// `None` for a press anywhere else (including the app's own
|
||||
/// buttons). The desktop runner consults this before its normal
|
||||
|
|
@ -334,6 +370,10 @@ impl TopBar {
|
|||
if rect_contains(figma_rect, point) {
|
||||
return Some(TopBarHit::OpenFigmaImport);
|
||||
}
|
||||
// Git-panel toggle, just right of the centred file name.
|
||||
if rect_contains(self.git_button_rect(rect), point) {
|
||||
return Some(TopBarHit::ToggleGitPanel);
|
||||
}
|
||||
// Right cluster: Maximize / Sun / Globe-with-chevron (right→left).
|
||||
// Maximize + Sun are normal ICON_BUTTON wide; Globe is
|
||||
// GLOBE_BUTTON_WIDTH wide because it carries a chevron.
|
||||
|
|
@ -546,6 +586,33 @@ impl Widget for TopBar {
|
|||
),
|
||||
);
|
||||
|
||||
// Git-panel button just right of the file name (TS GitButton):
|
||||
// a branch glyph + optional branch name. Always shown — a
|
||||
// click toggles the git panel (which offers `init` when the
|
||||
// doc isn't yet in a repo).
|
||||
let git_rect = self.git_button_rect(rect);
|
||||
draw_icon(
|
||||
cx.backend,
|
||||
Icon::GitBranch,
|
||||
Point2D::new(git_rect.origin.x, glyph_top(center_y, ICON_SIZE)),
|
||||
ICON_SIZE,
|
||||
self.theme.muted_foreground,
|
||||
1.4,
|
||||
);
|
||||
if let Some(branch) = self.git_branch.as_deref() {
|
||||
let label = TextLayout::single_run(
|
||||
branch,
|
||||
"system-ui",
|
||||
11.0,
|
||||
to_jian_color(self.theme.muted_foreground),
|
||||
Point2D::new(0.0, 0.0),
|
||||
);
|
||||
cx.backend.draw_text(
|
||||
&label,
|
||||
Point2D::new(git_rect.origin.x + ICON_SIZE + 6.0, center_y + 4.0),
|
||||
);
|
||||
}
|
||||
|
||||
// ── Right cluster ──────────────────────────────────────
|
||||
// Right → left: Maximize | Sun | Globe+Chevron. Globe is a
|
||||
// wider compound button (signals the dropdown affordance).
|
||||
|
|
@ -741,6 +808,14 @@ fn paint_figma_button(cx: &mut PaintCx<'_>, theme: &Theme, x: f32, center_y: f32
|
|||
);
|
||||
}
|
||||
|
||||
/// Rough "is this a full-width (CJK/Hangul/full-width-form) glyph"
|
||||
/// test — used only to estimate the rendered file-name width so the
|
||||
/// git button clears it.
|
||||
fn is_wide_glyph(c: char) -> bool {
|
||||
let cp = c as u32;
|
||||
matches!(cp, 0x1100..=0x11FF | 0x2E80..=0x9FFF | 0xAC00..=0xD7AF | 0xF900..=0xFAFF | 0xFF00..=0xFFEF)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
|
|
|||
|
|
@ -332,6 +332,25 @@ impl WidgetHostNative {
|
|||
self.mark_dirty();
|
||||
return true;
|
||||
}
|
||||
TopBarHit::ToggleGitPanel => {
|
||||
// Mirror `main.rs` A::ToggleGitPanel bookkeeping; the
|
||||
// binary's per-frame `if git_panel.open { refresh }`
|
||||
// performs the actual repo scan.
|
||||
let panel = &mut self.editor_state.editor_ui.git_panel;
|
||||
let opening = !panel.open;
|
||||
panel.open = opening;
|
||||
if opening {
|
||||
panel.loading = true;
|
||||
} else {
|
||||
panel.commit_focused = false;
|
||||
panel.remote_focused = false;
|
||||
panel.https_focused = false;
|
||||
panel.diff = None;
|
||||
panel.merge_resolve = None;
|
||||
}
|
||||
self.mark_dirty();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if rect_contains(top_bar_rect, Point2D::new(x, y)) {
|
||||
|
|
|
|||
|
|
@ -261,6 +261,9 @@ impl WidgetHost {
|
|||
TopBarHit::OpenFigmaImport => {
|
||||
self.editor_state.editor_ui.figma_import_open = true;
|
||||
}
|
||||
TopBarHit::ToggleGitPanel => {
|
||||
self.editor_state.editor_ui.git_panel.open ^= true;
|
||||
}
|
||||
}
|
||||
self.mark_dirty();
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Reference in a new issue