From ce423fddcc0c3a7333b1c7b2e69faaff4a2155b8 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Sun, 22 Feb 2026 15:17:20 -0500 Subject: [PATCH] start refactoring menubar and toolbar components --- src/kiri/app/init/sync.js | 7 +- src/kiri/app/menubar.js | 293 ++++++++++++++++++++++++++++++ src/kiri/app/mode.js | 1 + src/kiri/app/preferences.js | 1 + src/kiri/app/selected.js | 18 +- src/kiri/app/toolbar.js | 11 ++ src/kiri/app/view-mode.js | 4 +- src/load/svg.js | 2 +- src/main/kiri.js | 2 + src/main/void.js | 6 +- src/mesh/build.js | 2 +- web/kiri/index.css | 127 +++++-------- web/kiri/index.html | 350 ++++-------------------------------- web/moto/menubar.css | 126 +++++++++++++ web/moto/palette.css | 45 ++--- 15 files changed, 539 insertions(+), 456 deletions(-) create mode 100644 src/kiri/app/menubar.js create mode 100644 src/kiri/app/toolbar.js create mode 100644 web/moto/menubar.css diff --git a/src/kiri/app/init/sync.js b/src/kiri/app/init/sync.js index e3a1fba7..25b4a92b 100644 --- a/src/kiri/app/init/sync.js +++ b/src/kiri/app/init/sync.js @@ -221,7 +221,6 @@ function setup_keybd_nav() { // bind interface action elements ui.acct.help.onclick = (ev) => { ev.stopPropagation(); api.help.show() }; ui.acct.don8.onclick = (ev) => { ev.stopPropagation(); api.modal.show('don8') }; - ui.acct.mesh.onclick = (ev) => { ev.stopPropagation(); WIN.location = "/mesh" }; ui.acct.export.onclick = (ev) => { ev.stopPropagation(); settingsOps.export_profile() }; ui.acct.export.title = LANG.acct_xpo; ui.func.slice.onclick = (ev) => { ev.stopPropagation(); api.function.slice() }; @@ -251,10 +250,6 @@ function setup_keybd_nav() { $('view-arrange').onclick = api.platform.layout; $('view-top').onclick = space.view.top; $('view-home').onclick = space.view.home; - $('view-front').onclick = space.view.front; - $('view-back').onclick = space.view.back; - $('view-left').onclick = space.view.left; - $('view-right').onclick = space.view.right; $('unrotate').onclick = () => { api.widgets.for(w => w.unrotate()); @@ -313,7 +308,7 @@ function setup_keybd_nav() { $('context-setfocus').onclick = () => { view_tools.startFocus(ev => api.space.set_focus(undefined, ev.object.point)); }; - $('context-contents').onclick = api.const.SPACE.view.fit; + // $('context-contents').onclick = api.const.SPACE.view.fit; $('view-fit').onclick = api.const.SPACE.view.fit; $('wassup').onmouseover = () => { $('suppopp').classList.remove('hide') }; diff --git a/src/kiri/app/menubar.js b/src/kiri/app/menubar.js new file mode 100644 index 00000000..f289d196 --- /dev/null +++ b/src/kiri/app/menubar.js @@ -0,0 +1,293 @@ +/** Copyright Stewart Allen -- All Rights Reserved */ + +import { $ } from '../../moto/webui.js'; + +const MENUBAR_HTML = ` + + +
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + +
+
+
+ + +
+
+
+ +
+
+
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ +
+
+ +
+
+
+ + +
+
+ + +
+
+
+
+ +
+ +
+
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+
+
+
+ + + + + + + + + +
+ +
+
+
+
+
+ + + + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+ +
+
+ +
+
+
+ +
+
+
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+
+ +
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; + +export const menubar = { + build() { + const node = $('menubar'); + if (!node) { + return; + } + node.innerHTML = MENUBAR_HTML; + } +}; diff --git a/src/kiri/app/mode.js b/src/kiri/app/mode.js index 7f992d9d..fcae4a6c 100644 --- a/src/kiri/app/mode.js +++ b/src/kiri/app/mode.js @@ -63,6 +63,7 @@ function setMode(mode, lock, then) { // change mode constants current.mode = mode; MODE = MODES[mode]; + $('app-mode').innerText = mode; // gcode edit area for any non-SLA mode api.uc.setVisible($('gcode-edit'), mode !== 'SLA'); // highlight selected mode menu item diff --git a/src/kiri/app/preferences.js b/src/kiri/app/preferences.js index 3b32da5a..a2e12ff6 100644 --- a/src/kiri/app/preferences.js +++ b/src/kiri/app/preferences.js @@ -109,6 +109,7 @@ function booleanSave() { updateDrawer(); api.event.emit('boolean.update'); space.view.setProjection(control.ortho ? 'orthographic' : 'perspective'); + setDarkLight(control.dark); } function updateDrawer() { diff --git a/src/kiri/app/selected.js b/src/kiri/app/selected.js index b4421645..45f7e0cc 100644 --- a/src/kiri/app/selected.js +++ b/src/kiri/app/selected.js @@ -546,12 +546,12 @@ function parse_as_float(e) { function input_binding(ui) { // on enter but not on blur space.event.onEnterKey([ - ui.scale.X, (e) => input_scale(e, ui), - ui.scale.Y, (e) => input_scale(e, ui), - ui.scale.Z, (e) => input_scale(e, ui), - ui.size.X, (e) => input_resize(e, ui), - ui.size.Y, (e) => input_resize(e, ui), - ui.size.Z, (e) => input_resize(e, ui), + // ui.scale.X, (e) => input_scale(e, ui), + // ui.scale.Y, (e) => input_scale(e, ui), + // ui.scale.Z, (e) => input_scale(e, ui), + // ui.size.X, (e) => input_resize(e, ui), + // ui.size.Y, (e) => input_resize(e, ui), + // ui.size.Z, (e) => input_resize(e, ui), ]); // on enter and blur space.event.onEnterKey([ @@ -563,9 +563,9 @@ function input_binding(ui) { ui.toolShaftLen, updateTool, ui.toolTaperTip, updateTool, ui.toolTaperAngle, updateTool, - $('rot_x'), parse_as_float, - $('rot_y'), parse_as_float, - $('rot_z'), parse_as_float + // $('rot_x'), parse_as_float, + // $('rot_y'), parse_as_float, + // $('rot_z'), parse_as_float ], true); } diff --git a/src/kiri/app/toolbar.js b/src/kiri/app/toolbar.js new file mode 100644 index 00000000..d29d2363 --- /dev/null +++ b/src/kiri/app/toolbar.js @@ -0,0 +1,11 @@ +/** Copyright Stewart Allen -- All Rights Reserved */ + +import { menubar } from './menubar.js'; + +const toolbar = { + build() { + menubar.build(); + } +}; + +export { toolbar }; diff --git a/src/kiri/app/view-mode.js b/src/kiri/app/view-mode.js index dbb87dc9..a6a0d987 100644 --- a/src/kiri/app/view-mode.js +++ b/src/kiri/app/view-mode.js @@ -42,11 +42,11 @@ function setViewMode(mode) { ['view-arrange','act-slice','act-preview','act-animate'].forEach(el => { $(el).classList.remove('selected') }); - $('render-tools').classList.add('hide'); + // $('render-tools').classList.add('hide'); switch (mode) { case VIEWS.ARRANGE: $('view-arrange').classList.add('selected'); - $('render-tools').classList.remove('hide'); + // $('render-tools').classList.remove('hide'); api.function.clear_progress(); api.client.clear(); STACKS.clear(); diff --git a/src/load/svg.js b/src/load/svg.js index 8024b6f8..f3519afa 100644 --- a/src/load/svg.js +++ b/src/load/svg.js @@ -44,7 +44,7 @@ export function parse(text, opt = { }) { if (points.length < 3) { continue; } - let poly = newPolygon().addPoints(points.map(p => newPoint(p.x, -p.y, 0))); + let poly = newPolygon().addPoints(points.map(p => newPoint(p.x, -p.y, 0))).clean(); if (poly.appearsClosed()) poly.points.pop(); if (type === 'polyline') poly.setOpen(true); poly._svg = { width, miter }; diff --git a/src/main/kiri.js b/src/main/kiri.js index 8e360c8d..89f5d388 100644 --- a/src/main/kiri.js +++ b/src/main/kiri.js @@ -10,6 +10,7 @@ import { api } from '../kiri/app/api.js'; import { init_lang } from '../kiri/app/init/lang.js'; import { init_input } from '../kiri/app/init/input.js'; import { init_sync } from '../kiri/app/init/sync.js'; +import { toolbar } from '../kiri/app/toolbar.js'; let traceload = location.search.indexOf('traceload') > 0; let load = []; @@ -36,6 +37,7 @@ async function checkReady() { { api.client.start(); await init_lang(); + toolbar.build(); await init_input(); await init_sync(); } diff --git a/src/main/void.js b/src/main/void.js index b8b74a63..2f9f7366 100644 --- a/src/main/void.js +++ b/src/main/void.js @@ -305,6 +305,9 @@ async function init() { }); api.origin.syncOverlayPoint(); + // update canvas based on left panel size + space.event.onResize(); + // Hide loading curtain const curtain = $('curtain'); if (curtain) { @@ -315,9 +318,6 @@ async function init() { }, 300); } - // update canvas based on left panel size - space.event.onResize(); - console.log({ void_form_ready: true }); } diff --git a/src/mesh/build.js b/src/mesh/build.js index fc88e7e9..2c1ab8a8 100644 --- a/src/mesh/build.js +++ b/src/mesh/build.js @@ -396,7 +396,7 @@ function ui_build() { div('File'), div({ class: "menu-items" }, [ input({ - id: "import", type: "file", class: ["hide"], multiple: true, accept:".stl,.obj", + id: "import", type: "file", class: ["hide"], multiple: true, accept:".stl,.obj,.svg,.png", onchange(evt) { broker.send.load_files(evt.target.files) } }), menu_item('New', file.new), diff --git a/web/kiri/index.css b/web/kiri/index.css index 88cd2dc5..14448aaf 100644 --- a/web/kiri/index.css +++ b/web/kiri/index.css @@ -318,8 +318,7 @@ details[open] summary::after { .dark #render-tools .pop, .dark #render-tools svg, .dark .pop-tics > div, -.dark #top, -.dark #top .content, +.dark #menubar.content, .dark #app-name, .dark .set2-group, .dark .set2-group .var-row, @@ -390,7 +389,7 @@ details[open] summary::after { .dark #oplist div:hover .del { color: #777; } -.dark #top .content > div:hover { +.dark #menubar.content > div:hover { background-color: var(--blue-1); } .dark .top-menu label { @@ -449,7 +448,7 @@ details[open] summary::after { } /* top menu bar, drop menus */ -#top, #app-name { +#app-name { background-color: #fff; text-transform: capitalize; font-family: sans-serif; @@ -507,16 +506,17 @@ details[open] summary::after { .top-menu > span:hover .top-menu-drop { display: flex; } -.top-menu-left .content { +/* .top-menu-right .content { border-top-right-radius: 4px; -} -.top-menu-right { align-items: self-end; +} */ +.top-menu-left { + align-items: self-start; } .top-menu-center .content > div > label { text-align: center !important; } -.top-menu-right .content { +.top-menu-left .content { border-top-left-radius: 4px; } .top-menu-drop { @@ -532,7 +532,7 @@ details[open] summary::after { width: 15px; } -#top .content { +#menubar.content { gap: 2px; display: flex; align-items: center; @@ -545,63 +545,44 @@ details[open] summary::after { border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; } -#top .content { +#menubar.content { display: flex; flex-direction: column; align-items: stretch; padding: 2px; } -#top .content > div { +#menubar.content > div { display: flex; flex-direction: row; } -#top .content > div > label { +#menubar.content > div > label { text-align: left; flex-grow: 1; } -#top .content > div > span { +#menubar.content > div > span { text-align: right; } -#top .content > div > span { +#menubar.content > div > span { padding: 2px 7px 2px 7px; padding-left: 10px; text-align: center; } -#top .content > div > label { +#menubar.content > div > label { padding: 2px 7px 2px 7px; justify-self: stretch; align-self: stretch; border-radius: 3px; } -#top .content > div:hover { +#menubar.content > div:hover { background-color: var(--blue-4); } #app-name { - position: absolute; - top: 0; - left: 50%; - z-index: 50; - transform: translateX(-50%); -} -#app-name { - cursor: pointer; - -} -#app-name hr { - margin: 1px; -} -#app-name:hover #app-name-pop { - display: flex; -} -#app-name-pop { - color: var(--fg-gray); - font-family: sans-serif; - position: absolute; - top: 100%; -} -#app-name-pop .content { - text-align: center; + color: var(--appname-blue); + font-weight: bold; + align-self: center; + justify-self: stretch; + height: 100%; } #app,div { @@ -1164,59 +1145,39 @@ details[open] summary::after { background-color: var(--main-color); color: white; } - -/* top center toolbar */ -#render-tools { +/* mode toolbar */ +#mode-tools { pointer-events: all; - position: absolute; gap: 2px; - top: 3px; + top: 0; left: 0; right: 0; align-items: center; justify-content: center; flex-direction: row; } -#render-tools span { - position: relative; +#mode-tools > span { + text-transform: capitalize; + display: flex; + flex-direction: row; + align-items: center; + color: var(--menubar-fore); + background-color: var(--menubar-back); + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-left: 1px solid var(--border-gray); + border-right: 1px solid var(--border-gray); + border-bottom: 1px solid var(--border-gray); + padding: 3px 5px 3px 5px; } -#render-tools svg { - font-size: 20px; +#mode-tools svg { aspect-ratio: 1/1; - background-color: #fff; - border: 1px solid #aaa; - border-radius: 3px; - padding: 8px; + font-size: 20px; + padding: 0 5px 0 0; } -#render-tools svg:hover { - border: 1px solid blue; - background-color: var(--blue-4); -} -/** tool pop menus */ -#render-tools .pop:before { - position: absolute; - top: -10px; - left: -20px; - width: calc(100% + 40px); - height: calc(100% + 20px); - /* background-color: red; */ - content: ""; -} -#render-tools .pop { - background-color: #fff; - border: 1px solid #aaa; - border-radius: 3px; - position: absolute; - margin-top: 3px; - padding: 3px; - top: 100%; - left: 50%; - transform: translateX(-50%); - text-align: center; - white-space: nowrap; -} -#render-tools > span:not(:hover) .pop { - display: none; +#mode-tools > span:hover { + border-color: var(--appname-blue); + background-color: rgba(0,0,0,0.4); } /** fdm extruder drop-down */ #ft-nozzle .splat { @@ -2662,4 +2623,4 @@ details[open] summary::after { .devel #code-preview > div, .devel #code-preview-textarea { height: 100%; -} \ No newline at end of file +} diff --git a/web/kiri/index.html b/web/kiri/index.html index 3d42e7c0..56c4e2d4 100644 --- a/web/kiri/index.html +++ b/web/kiri/index.html @@ -19,16 +19,24 @@ Kiri:Moto + @@ -46,323 +54,33 @@
-
-
- - - - - - - - - - - - - - - - - - - - -
-
-
- - Kiri:Moto -
-
-
- -
-
-
- -
-
-
- -
-
- -
-
- -
-
-
-
-
-
- - -
-
-
- - - -
-
-
- - -
-
-
- - -
-
- - - - -
-
-
- - -
-
-
-
- - - -
-
-
- - -
-
- - -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- - -
-
-
-
- - - -
-
-
- - -
-
- - -
-
- - -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
- - - -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
- - - -
-
-
- -
-
- -
-
-
-
- - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
loading
-
-
- -
-
- -
-
- -
- -
- -
- -
- -
- -
- -
-
-
- -
-
-
-
- - - - - - - - - -
- -
-
-
- -
-
-
-
-
-
-
-
-
- - -
mirror selection
-
- - -
duplicate selection
-
- - -
choose a face to place
on the work surface
-
- - -
choose a face to align
to the y axis
-
- - -
choose focal point
camera orbit center
-
- - -
fit workspace contents
-
- - -
render objects solid
-
- - -
render objects wireframe
-
- - -
render objects transparent
-
- - -
trace edges
-
-
+
+ + + arrange + + + + + + + + + + + + + + + + +
diff --git a/web/moto/menubar.css b/web/moto/menubar.css new file mode 100644 index 00000000..c52f49bc --- /dev/null +++ b/web/moto/menubar.css @@ -0,0 +1,126 @@ +#menubar { + position: relative; + z-index: 50; + background-color: var(--menubar-back); + color: var(--menubar-fore); + text-transform: capitalize; + align-items: center; + border-bottom: 1px solid var(--border-gray); +} + +.menubar-separator { + align-self: stretch; + align-items: center; + background: var(--menubar-vsep); + margin: 5px; + width: 1px; +} + +.menubar-appname, +.menubar-mode { + color: var(--appname-blue); + cursor: default; + align-self: stretch; + align-items: center; + margin: 4px 0 4px 0; + padding: 4px 12px 4px 12px; + border-radius: 0; + user-select: none; +} + +.menubar-appname { + font-weight: bold; +} + +#menubar .top-menu { + display: flex; + align-items: stretch; + white-space: nowrap; +} + +#menubar .top-menu > span { + cursor: default; + position: relative; + display: flex; + gap: 8px; + align-items: center; + margin: 2px; + padding: 8px 12px; + border: 1px solid transparent; + border-radius: 6px; + user-select: none; +} + +#menubar .top-menu > span:hover { + border-color: var(--appname-blue); + background-color: rgba(0,0,0,0.4); +} + +#menubar .top-menu > span:hover .top-menu-drop { + display: flex; +} + +#menubar .top-menu label, +#menubar .top-menu svg { + color: inherit; +} + +#menubar .top-menu hr { + width: 100%; + margin: 0; + border: 0; + border-top: 0.5px solid var(--menubar-vsep); +} + +#menubar .top-menu-drop { + display: none; + position: absolute; + top: 100%; + left: 0; + z-index: 90; + font-family: sans-serif; + padding-top: 3px; +} + +#menubar .top-menu-right { + left: auto; + right: 0; +} + +#menubar .top-menu-drop .content { + display: flex; + flex-direction: column; + gap: 6px; + border: 1px solid var(--border-gray); + border-radius: 6px; + background: var(--menubar-back); + color: var(--menubar-fore); + padding: 4px; +} + +#menubar .top-menu-drop .content > div { + display: flex; + align-items: center; + gap: 15px; + border: 1px solid transparent; + border-radius: 6px; + padding: 4px 8px; +} + +#menubar .top-menu-drop .content > div > label { + flex-grow: 1; + text-align: left; +} + +#menubar .top-menu-drop .content > div > span { + display: flex; + justify-content: flex-end; + min-width: 16px; +} + +#menubar .top-menu-drop .content > div:hover, +#menubar .top-menu-drop .content > div.selected, +#menubar .top-menu > span.selected { + border-color: var(--appname-blue); + background-color: rgba(0,0,0,0.4); +} diff --git a/web/moto/palette.css b/web/moto/palette.css index 3dbbef2b..76a6ffab 100644 --- a/web/moto/palette.css +++ b/web/moto/palette.css @@ -4,43 +4,18 @@ */ :root { - /* semantic core */ - --color-bg: #f6f8fb; - --color-bg-elev: #ffffff; - --color-bg-subtle: #eef2f7; - --color-surface: #ffffff; - --color-surface-2: #f3f6fb; - --color-text: #1b2430; - --color-text-muted: #556173; - --color-border: #a6b3c3; - --color-border-strong: #6a7a90; - --color-accent: #5a9fd4; - --color-accent-hover: #7bb8e8; - --color-focus: rgba(90,159,212,0.35); - --color-selection: rgba(90,159,212,0.45); - --color-selection-hover: rgba(90,159,212,0.8); - --color-success: #4ade80; - --color-warning: #fbbf24; - --color-danger: #f87171; + --appname-blue: #5a9fd4; + --menubar-vsep: rgba(0,0,0,0.2); + --menubar-back: rgba(128,128,128,0.5); + --menubar-fore: rgba(20,20,20,1.0); + --border-gray: rgba(128,128,128,0.5); } :root.dark, :root[data-theme="dark"] { - --color-bg: #0f1116; - --color-bg-elev: #161a22; - --color-bg-subtle: #1b2230; - --color-surface: #1a1f29; - --color-surface-2: #222936; - --color-text: #e2e8f0; - --color-text-muted: #a5b0c0; - --color-border: #444f63; - --color-border-strong: #6d7a93; - --color-accent: #5a9fd4; - --color-accent-hover: #7bb8e8; - --color-focus: rgba(90,159,212,0.4); - --color-selection: rgba(90,159,212,0.5); - --color-selection-hover: rgba(90,159,212,0.95); - --color-success: #4ade80; - --color-warning: #fbbf24; - --color-danger: #f87171; + --appname-blue: #5a9fd4; + --menubar-vsep: rgba(255,255,255,0.2); + --menubar-back: rgba(50,50,50,0.9); + --menubar-fore: rgba(250,250,250,1.0); + --border-gray: rgba(128,128,128,0.5); }