Commit graph

1813 commits

Author SHA1 Message Date
Kayshen-X f3e7a149ef refactor(editor): render property checkboxes/radio via jian Checkbox/Radio
The widget + size-section check rows and the flex gap-alignment radio
now paint through jian Checkbox / Radio (first consumers) instead of
hand-rolled box+check / ring+dot; row hit-tests are unchanged.
2026-06-20 12:27:22 +08:00
Kayshen-X 962cfae904 refactor(editor): drop dead duplicate paint_flex_section
property_panel_sections::paint_flex_section was an unreferenced leftover
from when the flex section moved to property_panel_flex (the only wired
paint_flex_section). Removes the stale gapped-cell duplicate.
2026-06-20 12:21:08 +08:00
Kayshen-X 9ec653265c refactor(editor): migrate flex-direction toggle to jian ToggleGroup
The Free/Vertical/Horizontal layout-direction icon selector renders
through jian ToggleGroup (icon segments, font_size 14 → 18px icons) over
the same footprint; its hit walker switches to the continuous even cells
ToggleGroup paints so paint + hit stay aligned.
2026-06-20 12:19:17 +08:00
Kayshen-X be2c359402 refactor(editor): migrate text align toggles to jian ToggleGroup
The horizontal/vertical text-align icon selectors render through jian
ToggleGroup (icon segments, font_size 12 → 16px icons); their hit cells
switch from gapped to the continuous even cells ToggleGroup paints so
paint + hit stay aligned.
2026-06-20 12:16:26 +08:00
Kayshen-X c0e7ab60de refactor(editor): migrate text-growth toggle to jian ToggleGroup
The Auto/Fixed-width/Fixed-width+height text-growth selector renders
through jian ToggleGroup; its hit walker switches from gapped cells to
the continuous even cells ToggleGroup paints, so paint + hit stay aligned
with no inter-cell dead zones.
2026-06-20 12:14:18 +08:00
Kayshen-X 4045ffc163 refactor(editor): migrate image-fill mode control to jian ToggleGroup
The Contain/Cover/Stretch mode selector renders through jian ToggleGroup
(even cells aligned with its existing full-cell hit walker) instead of a
hand-rolled muted track + inset chip loop; active cell fills primary.
2026-06-20 12:11:12 +08:00
Kayshen-X 5e7302222b refactor(editor): migrate builtin-agent kind toggle to jian ToggleGroup
The Anthropic/OpenAI kind segmented control now renders + hit-tests
through jian ToggleGroup (segment_at) instead of a hand-rolled cell
loop + kind_option_rect. Drops the KindOption.slot indirection and the
kind_option_rect helper; single-option presets render full-width.
Bumps vendor/jian to 3b5db91.
2026-06-20 12:05:41 +08:00
Kayshen-X 2096a1f444 refactor(editor): adopt jian Button icon_paths + migrate code icon buttons
All op-editor-ui jian Button call sites move from icon_d to icon_paths.
The code panel's Generate / Export-bundle icon+label buttons and the
Design-MD action buttons now render through jian Button with full
multi-subpath icons (sparkles / braces / wand), dropping the local
paint_centered_icon_label hand-rolling + paint_primary_hover_overlay.
Bumps vendor/jian to 9998df9.
2026-06-20 11:54:56 +08:00
Kayshen-X 9f70adede7 refactor(editor): migrate export/code/image CTA buttons to jian Button
Export-section, export-dialog (Cancel→Outline, Export→Primary), image
generate-popover (Apply→Primary, Retry→Outline) and the code-panel
full-width action button now render through jian Button instead of
hand-rolled fill_round_rect + hover overlay + centered draw_text. The
solid-fill hover-darken now lives in the component, so per-button hover
state threads straight through. Bumps vendor/jian to 330feb4.
2026-06-20 11:47:55 +08:00
Kayshen-X 03e37f4613 refactor(editor): migrate provider-card connect/disconnect to jian Button
Connect renders through jian Button Primary (centered label, primary
fill) and Disconnect through the new DestructiveOutline variant (red
border + red label) instead of hand-rolled fill_round_rect + centered
draw_text. Bumps vendor/jian to 9e47bd3.
2026-06-20 11:38:42 +08:00
Kayshen-X 9c645584ff refactor(editor): migrate fill-type + design-md buttons to jian components
Fill section head-row fill-type dropdown now renders through jian
SelectTrigger (Outline box + chevron + own hover/press feedback)
instead of a hand-rolled label+glyph; the Design-MD empty-state action
buttons render through jian Button (Secondary, muted fill) so the CTA
affordance and feedback are the component's concern, not the panel's.
Drops the now-dead label_char_w helper.
2026-06-20 11:34:04 +08:00
Kayshen-X c887413074 refactor(editor): sink top_bar + settings + export dropdowns/buttons to jian
TopBar globe + file-menu triggers -> SelectTrigger (icon variant); agent-settings ProviderSelect/ProviderField + property-panel export format/scale dropdowns -> SelectTrigger (text); git_panel_diff glyph buttons -> jian Button(label). Removed the obsolete locale-glyph centering helper+const+test (SelectTrigger owns that now). SKIPPED (correctly): brand-logo buttons, the TopBar agent chip (compound), git branch button (multi-path icon + left-aligned). 6-agent workflow + central verify.
2026-06-20 11:27:25 +08:00
Kayshen-X c10a6638a9 chore(editor): SelectTrigger icon_paths field; bump jian 2026-06-20 11:16:46 +08:00
Kayshen-X d4cd38333f refactor(editor): sink component-browser kit dropdown to jian SelectTrigger
The kit-filter dropdown trigger (feedback wash + border + truncated label + chevron) now renders via jian SelectTrigger — one component call, feedback/label/chevron all internal. Demonstrates the dropdown 收口 pattern. Bumps vendor/jian to 144eb50.
2026-06-20 11:09:16 +08:00
Kayshen-X 27d5d0aae1 refactor(editor): sink scattered icon buttons to jian IconButton
top_bar paint_icon_button, design_md icon_button, and the align-toolbar align-icon row now render via jian IconButton instead of hand-rolling feedback + draw_icon. Their hover/active rendering is now the component's concern. align-toolbar idle icons go muted_foreground (shadcn toolbar look). Left compound (icon+chevron/brand-logo), labelled, and text-glyph buttons untouched — they aren't single lucide-icon buttons.
2026-06-20 11:01:34 +08:00
Kayshen-X a9bf1448a3 refactor(editor): toolbar icon buttons use jian IconButton; drop OP copy
toolbar's paint_button now renders jian IconButton (icon.paths() -> generic d-strings); removed the OP-local IconButton struct + paint_icon_button helpers from button.rs (the component now lives in jian). Bumps vendor/jian to 346eeb3. Other scattered icon buttons migrate next.
2026-06-20 10:54:40 +08:00
Kayshen-X 8eef1188ce refactor(editor): unify toolbar icon buttons into one paint_icon_button helper
Adds button::paint_icon_button (full icon button = hover/pressed/active feedback on jian Button + centred icon) and paint_icon_button_feedback (the bg+active funnel). toolbar's paint_button now delegates to it instead of hand-rolling active-fill + ghost-feedback + draw_icon separately. All toolbar icon buttons (tool buttons + shape slot) now funnel hover/active rendering through one place. Active highlight now jian Button Primary (r6). Removed dead BUTTON_RADIUS.
2026-06-20 10:38:42 +08:00
Kayshen-X f763e2f339 refactor(editor): split acp text helpers out to satisfy 800-line cap
agent_settings_acp.rs was over the 800-line cap (817 after the Card sink; ~812 before); moved draw_text + ellipsize into agent_settings_acp_helpers.rs. File now 798 lines, op-editor-ui clean.
2026-06-20 10:19:26 +08:00
Kayshen-X ed4154d91c refactor(editor): sink remaining agent-settings cards to jian Card
MCP server card + ACP agent card + 2 built-in provider cards (muted fill + border, r8/r10) now route through jian Card, looks preserved. The whole agent-settings card cluster (7 cards) now shares the canonical primitive.
2026-06-20 10:07:58 +08:00
Kayshen-X 07e1101eb0 refactor(editor): sink MCP + System settings cards to jian Card
agent_settings_mcp client-config card (card fill, r8) + agent_settings_system auto-update card (muted fill, r10) now route their chrome through jian Card, looks preserved. Three agent-settings cards now share the canonical primitive.
2026-06-20 09:06:06 +08:00
Kayshen-X 2d9ccce73a refactor(editor): sink agent provider card chrome to jian Card
paint_agent_card's hand-rolled conditional fill_round_rect + stroke_round_rect chrome now goes through jian Card; the fill choice (outlined ClaudeCode -> muted, hover -> accent, else transparent) stays caller-side so the look is preserved exactly (radius 10, border). Bumps vendor/jian to 5f903d6. Demonstrates the enhance-jian-then-sink pattern.
2026-06-20 08:59:17 +08:00
Kayshen-X 3e54a66f31 chore(vendor): bump jian — Select check-left + Switch hover fidelity 2026-06-20 08:29:33 +08:00
Kayshen-X d68b959c98 chore(vendor): bump jian to f02b4a5 — layout_scene 800-line split 2026-06-20 08:16:57 +08:00
Kayshen-X a004a95b79 chore(vendor): bump jian to fd4111f — Input field 2026-06-20 07:57:04 +08:00
Kayshen-X 65b5bf8a6b chore(vendor): bump jian to c12f277 — Swatch/Tooltip/Tabs/ToggleGroup/Accordion/Popover 2026-06-20 07:54:01 +08:00
Kayshen-X 64a898f71a fix(canvas): skip colour-drag scene patch for Ref/slotless anchors
Codex review of the web twin flagged a Ref-anchor mismatch: set_selected_color
is a no-op on a Ref (it carries no fill/stroke slot), so the doc write does not
land — yet the scene patch would still mutate the Ref's scene node, briefly
showing a colour the document never received (snapping back on release). Native
caught the common case via its instance-write redirect, but a non-redirected
Ref (and any gradient-only / slotless node) slipped through on both paths.

Gate both try_patch_color_drag paths on the freshly-written hex actually being
present (first_solid_fill_hex / first_solid_stroke_hex); absent → the write did
not land → fall back to the full rebuild. Same conservative guard on native +
web.
2026-06-20 02:27:31 +08:00
Kayshen-X 6ee455f7b1 perf(canvas): patch scene fill/stroke in place on web colour-picker drag
Web twin of 8b457a50/9056458c: a colour-picker drag rebuilt the whole layout
per mouse-move (doc fill changed → scene cache miss → taffy + reshape) though
a solid colour touches no layout. try_patch_color_drag patches the anchor's
resolved scene fill / stroke via LayoutScene::set_node_fill /
set_node_stroke_color (folding paint-body + node opacity) and invalidates the
cache. The patch path still flags doc_sync_dirty (live-canvas push) but skips
the scene rebuild — reachable from this descendant module without touching the
spine. Variable-mode / gradient-stop / effect / new-stroke fall back to rebuild.
2026-06-20 01:38:40 +08:00
Kayshen-X f2c074d9d3 fix(canvas): bake paint-body opacity into the colour-drag scene patch
Codex review caught a BLOCKER: the loader folds TWO opacity factors into
resolved scene paint alpha — the fill/stroke body's own opacity (apply_alpha
in style_payload) AND node cumulative opacity — but the colour-drag fast path
only baked node opacity, so a fill/stroke authored below 100% painted too
opaque on every drag frame until release reconciled. Fold the body opacity in
host-side via first_solid_fill_opacity / new first_solid_stroke_opacity before
the patch; jian-scene still bakes node opacity on top, matching scene-build.
+unit test for the new stroke-opacity accessor.
2026-06-20 01:18:37 +08:00
Kayshen-X d653cd4b33 chore(vendor): bump jian to afe3fc8 — Separator + Progress 2026-06-20 00:49:33 +08:00
Kayshen-X c354b0b6b2 chore(vendor): bump jian to 199268e — Button Secondary/Link + Badge/Checkbox/Radio/Card 2026-06-20 00:45:40 +08:00
Kayshen-X e839c40770 perf(canvas): patch scene fill/stroke in place on colour-picker drag
A colour-picker drag rewrites doc fill on every mouse-move, so the scene
build cache (which compares the doc) rebuilt the whole layout — taffy + a
full SceneNode reshape — per drag frame, even though a solid colour change
touches no layout. Mirror the node-drag fast path: patch the anchor's
resolved scene fill / stroke via LayoutScene::set_node_fill /
set_node_stroke_color and invalidate the cache, skipping mark_dirty so the
patch survives the frame. Variable-mode, instance redirects, gradient-stop /
effect targets, and brand-new strokes fall back to the full rebuild.

Bumps vendor/jian to a86832d (the scene-patch methods). Native only; the
web host's live-sync push gate needs the same wiring once its spine settles.
2026-06-20 00:44:06 +08:00
Kayshen-X 25a5b02ce2 refactor(editor): sink agent-settings switch into jian Switch
paint_settings_switch dropped its hand-rolled track+thumb paint and now delegates to jian Switch (geometry identical: knob 16, inset 2). Removes the duplicated switch paint; off-track is now the shadcn input token. Hit stays host-side rect.contains (behavior-identical on desktop). Bumps vendor/jian to 2708666. First Phase A component sink.
2026-06-20 00:27:35 +08:00
Kayshen-X 6e43abd5ef feat(editor): add shadcn input/ring/secondary/destructive-foreground tokens to Theme
Theme gains the canonical shadcn fields; button::tokens_from_theme maps them into jian Tokens (+ radius 6.0). Unblocks the Switch off-track=input reconciliation and Button secondary variant. Bumps vendor/jian to 9cd5d50.
2026-06-20 00:24:00 +08:00
Kayshen-X fef880b8a5 chore(lock): reconcile Cargo.lock with jian-scene dep edits
Add jian-scene; drop op-editor-ui from op-mcp/op-pen-loader — matches the
scene-unification Cargo.toml changes so the lock isn't stale.
2026-06-20 00:16:24 +08:00
Kayshen-X eb02c293d2 refactor(editor): hoist relative-alpha + over helpers into util
6 git_panel modules each duplicated fn alpha (RELATIVE: multiplies c.a*factor) and git_panel_empty duplicated over(). Hoisted to util::alpha / util::over (single source); locals now delegate. NOTE: align_toolbar::alpha SETS absolute alpha (Color{a,..}) — a different op (= Color::with_alpha), deliberately left separate. Part of atomic-sink Phase 0.4.
2026-06-20 00:11:58 +08:00
Kayshen-X f5c1ef555f docs(crates): note scene moved to jian-scene + scene_vars to op-editor-core 2026-06-20 00:08:18 +08:00
Kayshen-X 00599838cf refactor(editor): collapse 6 tokens_from_theme copies to one canonical
ai_chat_input_text / property_panel_fill_picker / property_panel_text_input / agent_settings_caret / locale_picker / git_panel_text each duplicated the byte-identical Theme->jian Tokens map. They now delegate to the canonical button::tokens_from_theme; unused Density imports dropped. -114 net lines, no behavior change. Part of atomic-sink Phase 0.3.
2026-06-20 00:06:50 +08:00
Kayshen-X 4fb17fb54c perf(canvas): cache parsed SVG paths in the CanvasKit bridge
Every chrome icon / lucide glyph / brand logo / vector node re-parsed its d
string via CK.Path.MakeFromSVGString on every frame. Cache the parsed,
untransformed path keyed on d; callers draw a .copy() they transform + delete,
leaving the cached original pristine. Bounded (1024) with wasm-heap cleanup on
overflow. Mirrors the native svg_path_cache. Verified on :3100 — icons render
identically, no JS errors.
2026-06-19 23:59:17 +08:00
Kayshen-X 1009124332 refactor(pen-loader): use jian-scene + op-editor-core, drop op-editor-ui
Scene types -> jian_scene::layout_scene; scene_vars -> op_editor_core::scene_vars;
geometry/image -> op_editor_core::render_backend. Builder editor_state_to_layout_scene
stays here. 76+3 tests green; no op_editor_ui ref left.
2026-06-19 23:58:07 +08:00
Kayshen-X 26e9d2fa55 chore(vendor): bump jian to eb58f8f — Switch::hit 2026-06-19 23:49:30 +08:00
Kayshen-X bfef05ca13 refactor(mcp): use jian-scene, drop op-editor-ui dep
read_tools imports NodeKind/SceneNode from jian-scene; scene values still
come from op-pen-loader's builder. 314 tests green; no op_editor_ui ref left.
2026-06-19 23:46:03 +08:00
Kayshen-X 9add35583c refactor(editor): source CursorHint from jian-core; host owns handle+Pointer map
CursorHint now lives in jian-core (re-exported via op_host_native). for_handle becomes the host free fn cursor_for_handle (depends on OP SelectionHandle). Adds a Pointer arm to the desktop CursorIcon map. Behavior preserved; bumps vendor/jian to 44c7b75.
2026-06-19 23:42:30 +08:00
Kayshen-X 71fa9baa5b refactor(editor-ui): re-export scene from jian-scene/op-editor-core
Delete the moved modules (layout_scene, layout_scene_hit, scene_vars + their
tests); shim re-export jian_scene::{layout_scene,layout_scene_hit} +
op_editor_core::scene_vars so every consumer path (incl. dirty hosts) resolves
unchanged. Paint imports path geometry from jian-scene. 647 tests green.
2026-06-19 23:39:02 +08:00
Kayshen-X d76ba4528d refactor(editor-core): move scene_vars in from op-editor-ui
VariableTable/Value/Scalar (unresolved theme refs + NodeId) now live with
the canonical variable system. NodeId/Color resolve at the op-editor-core
crate root. 26 scene_vars tests green.
2026-06-19 23:18:43 +08:00
Kayshen-X 210fc21bf6 chore(vendor): bump jian submodule — jian-scene crate + scene skeleton removal 2026-06-19 23:12:30 +08:00
Kayshen-X 7678352071 ci: fix stale op-web-daemon path after crate rename to op-host-services
wasm-bundle-build.yml comment still pointed at crates/op-web-daemon/src/web_static.rs;
the rename sweep covered crates/Dockerfile/tools but not .github/. Now op-host-services.
2026-06-19 22:41:43 +08:00
Kayshen-X 88a571c028 refactor(host): rename op-web-daemon crate to op-host-services
The extracted headless crate is consumed by BOTH op-host-desktop (the GUI binary, for its
embedded --serve-web/MCP/chat/export) AND op-host-web-server — so 'web-daemon' was misleading.
Renamed crate dir + package + lib (op_web_daemon -> op_host_services) across all consumer files
(114 refs in 24 files) + the 4 Cargo.toml deps + Dockerfile/guard comments; identity docs
rewritten (it's the GUI-free host backend — daemon/MCP/AI/export/persistence — not web-specific).
No behavior change. (Lock renamed accordingly; the concurrent actor's op-host-web serde line excluded.)
2026-06-19 22:35:22 +08:00
Kayshen-X b7951fc598 ci(host): build web image from op-host-web-server + headless-boundary guard (Phase 6, Tasks 6.2-6.4)
Dockerfile.web-rust builds -p op-host-web-server (was op-host-desktop) and drops ALL GL/X11
build + runtime apt deps (libegl/libgles/libgbm/libxkbcommon/libwayland/libxcb) — the raster
server links none; only freetype/fontconfig + CJK fonts remain for skia text. COPY + CMD repointed
to /app/op-host-web-server. New tools/check-web-server-headless.sh fails CI if op-host-web-server's
isolated dep graph pulls winit/glutin/casement/muda/accesskit-adapters or skia-safe with gl (bare
accesskit core allowed per Codex Issue 1); wired into rust-check.yml + its paths filter. Stale
web_static.rs path comment fixed (op-host-desktop -> op-web-daemon). Desktop-app build job untouched.
2026-06-19 22:14:56 +08:00
Kayshen-X f198cdf76a feat(host): add headless op-host-web-server binary (Phase 6, Task 6.1)
A thin binary linking ONLY op-web-daemon — no winit/glutin/muda/accesskit-adapters/skia-GL.
Routes --serve-web/--mcp/--mcp-http argv to op_web_daemon::web_canvas_server::run_web_canvas +
op_web_daemon::mcp_serve::{run,run_http} (mirrors the desktop dispatcher, headless-only — no GUI
fallback). Added to root default-members. VERIFIED via cargo tree: 0 winit/glutin/casement/muda/
accesskit-adapters + skia-safe without gl (raster) — the web-server image now excludes all
desktop/GL code, answering the original question. (Lock also drops the actor-removed op-app crate.)
2026-06-19 22:09:58 +08:00
Kayshen-X c6743453b6 refactor(host): move web_canvas_server + web_chat_standard, daemon fully in op-web-daemon (Phase 5, Task 5.3)
The web-canvas daemon (web_canvas_server + its #[path] tests) + the CLI standard-mode
chat handler (web_chat_standard) — the mutually-coupled top of the closure — move together
to op_web_daemon; all their op_web_daemon::* refs flip to crate:: (the daemon is now
self-contained intra-crate). The op-host-desktop mcp_serve residual dispatcher's --serve-web
arm repoints to op_web_daemon::web_canvas_server::{parse_serve_web_args, run_web_canvas}.
WebCanvasState::new marked #[cfg(test)] (test-only callers) — resolves a long-standing
dead_code warning. op-host-desktop now holds only the GUI host + argv dispatcher; the
headless daemon is entirely in op-web-daemon. op-web-daemon 326 tests green, 0 warnings.
2026-06-19 22:01:31 +08:00