The Git popover is hit-tested at press block 0.9 — ahead of the align
toolbar (line 554) — but was painted at §8.2, BELOW the align toolbar
(§8.4). That was moot while the panel floated top-left, but once it
centres under the Git button it overlaps the align toolbar: paint said
the align toolbar was on top, the hit-test said the popover was, so a
click on an align button over the popover went to the popover.
Move the popover paint to §8.7 — above the align toolbar / marquee /
property overlays, still below the shape / locale pickers and modals —
so the paint z-order matches the hit-test priority.
Faithful port of apps/web's git-panel-empty-state.tsx:
- Per-card hover effect (TS hover:/group-hover:): the card lifts 1px and
recolors to border-primary/40 + bg-accent/30, the icon box to
bg-primary/10 + text-primary. Tracked via the new
GitPanelState.empty_hovered_card (0=Init / 1=Open / 2=Clone), updated
by update_git_panel_empty_hover on cursor-move.
- Disabled Init card (no saved .op): the TS opacity-50 look + a
not-allowed cursor (new CursorHint::NotAllowed → winit NotAllowed),
and the requireSavedFile hint shown only on hover (TS Tooltip
side="bottom", bg-primary text-primary-foreground).
- Gradient clock badge (from-muted/60 to-muted/20 + ring-border/60) and
the TS container spacing (pt-8 / gap-5 / pb-6).
Adds the alpha()/over() colour helpers (Tailwind /NN opacity + compositing)
and a placement test for the per-card hover + not-allowed cursor.
- Float the git panel centered under the TopBar git button (TS popover
parity) with an up-caret; git_panel_rect is the single placement source
that paint, hit-test, cursor and outside-click all read.
- git_panel_outer_rect (body + caret bridge) backs hit-test / cursor /
outside-click / diff-scroll so a click or hover on the caret is caught
by the popover instead of falling through to the canvas.
- over_floating_overlay keeps the canvas Move/Crosshair cursor from
bleeding through every floating overlay (git / status / chat / toolbar /
align-toolbar / shape / locale / file-menu / context-menu + the centered
panels).
- Onboarding empty state: Init / Open / Clone cards; Init is disabled until
the doc has a saved path, with a hover-gated "save .op first" hint pill.
- Split oversized files for the 800-line cap: git_panel -> {empty, status};
geometry -> overlay_rects; top_bar -> top_bar_paint.
- Resolve the stash-pop conflict against the upstream refactor (ai_chat_rect
now lives in ai_chat_geometry) and clear clippy-1.94 drift in upstream
files (unnecessary_map_or, too_many_arguments, match_like_matches_macro)
so the workspace gate passes.
The onboarding cards are now actionable:
- 新建/Init → `GitRepo::init` at the saved doc's directory, then
rebind the session so the doc is tracked (disabled until saved);
- 打开/Open → native folder picker → `GitRepo::discover` + a new
`GitSession::bind_repo` (tracks the doc when it's under the repo);
- 克隆/Clone → info dialog for now (needs the in-panel URL form — a
follow-up).
Adds GitPanelHit::{EmptyInit,EmptyOpen,EmptyClone},
GitPanelAction::{InitRepo,OpenRepo,CloneRepo}, host press dispatch +
binary drain, `git_panel.has_saved_file` tracked on every rebind, and
a hit-test test. EN/ZH strings for the two new messages.
Replace the bare "不是 Git 仓库。" text with the TS onboarding empty
state: a History clock glyph in a rounded box, the
"这份文件还没有版本历史" heading, three cards (新建/打开/克隆 with
FilePlus/FolderOpen/GitFork icons + descriptions), and the "Git is
optional" note — laid out centred in a 380×284 panel.
- new History/FilePlus/GitFork icons;
- `GitPanelState.has_saved_file` dims the Init card when the doc is
unsaved (matching TS);
- `empty_state_rects` shared for the upcoming card hit-test.
Card actions (init/open/clone) wired in a follow-up.
The web/wasm build has no git backend and never paints GitPanel, so
the top-bar git button toggled an invisible panel (Codex stop-time
review). Gate the button's paint + hit-test on a `GIT_BUTTON_AVAILABLE`
const (`!cfg!(target_arch = "wasm32")`) so it only exists on desktop.
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`.
Hangul codepoints were routed to the shared CJK typeface, which is
resolved from a Han ideograph (a Chinese font with no Hangul glyphs),
so 한국어 painted as blank .notdef boxes in the locale picker while
Chinese/Japanese/Hindi/Thai/Vietnamese rendered fine. Add a dedicated
`is_hangul_codepoint` split + a cached `korean_typeface` (resolved from
'한' → Apple SD Gothic Neo / Noto Sans KR) and route Hangul there in
both typeface-resolution paths.
The new sidebar↔file-menu divider shifted the folder button right, but
`TopBar::file_menu_rect` (the dropdown anchor) still used the pre-divider
x, so the file menu opened left of its button (Codex stop-time review).
Route the anchor through the divider span and have hit_test reuse
`file_menu_rect` so paint / hit-test / anchor can't drift again.
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.
Mirror the native host on the web backend:
- ArrowLeft/Right move the inline-rename caret (`apply_rename_caret`)
before falling through to node-nudge;
- StatusBar search icon frames the active page content
(`status_bar_search_hit` + `zoom_to_fit`, reusing `canvas_region` +
`LayoutScene::content_bounds` + `Viewport::fit_to`).
Type-checks on the host target; the wasm bundle build still needs EMSDK.
- add a 1px×14px divider between the agent/MCP chip and the locale
button (TS `w-px h-3.5 bg-border/60`) so the status chip reads as a
separate group;
- chip text 12→11px in muted-foreground, status dot 8→6px in
emerald-500 (#10b981) — matches the TS chip density/colour.
Note: the chip showing "Agents & MCP" vs "N agent · M MCP" is
connection state (0 connected agents/MCP → the set-up label), not a
layout bug.
Node-level opacity was folded into fill/stroke/gradient/shadow alpha at
scene-build, but rasters carry no colour to bake into, so image nodes
rendered fully opaque (codex stop-time review). Carry cumulative opacity
on `SceneNode` and modulate the image paint's alpha in the native draw
path (`draw_image_with_options` gains an `opacity` arg; trait default +
web fall back to opaque).