kiosk: pi-friendly compact mode + chromium 72 fallbacks

- Detect kiosk mode (localhost / ?kiosk=1) and add html.kiosk-mode
- Suppress 3D path-viewer in kiosk mode (Pi 3B too slow)
- Compact 1366x768 layout: 56px header, smaller jog grid, 4-col macros
  2-col status, 540px jog column
- Flex-gap fallbacks for Chromium 72 (header tabs, sys-btn, state-badge,
  ktab, sp-row, etc.) using "> * + *" margin-* rules
- Path-viewer: opaque WebGL canvas, ResizeObserver-gated render loop,
  no first-frame size flash
- Path-viewer renderer cleared properly on component teardown
- W axis row: W- | W+ | Probe XYZ | Probe Z (was W-|HomeW|W+|Probe)
- Running panel only for actual program execution (not jogging)
- Settings sectioned (Display+Units / Probing / G-code+Motion)
- Routed component now keep-alive across tab swaps
- FA4 -> FA6 webfonts
This commit is contained in:
muehe
2026-05-01 11:05:39 +02:00
parent 3d73e6c59d
commit 41d720c1d0
34 changed files with 1018 additions and 126 deletions

View File

@@ -52,7 +52,7 @@ script#console-view-template(type="text/x-template")
// ----- Messages -----
.messages-pane(v-show="sub === 'messages'")
.msg-empty(v-if="!$root.messages_log.length")
.fa.fa-check-circle
.fa.fa-circle-check
|  No messages.
.msg(v-for="m in $root.messages_log",
:class="m.level === 'warning' ? 'warn' : 'info'", track-by="$index")

View File

@@ -35,8 +35,9 @@ script#control-view-template(type="text/x-template")
button.pure-button.button-error(@click="GCodeNotFound=false") OK
message(:show.sync="show_probe_dialog")
h3(slot="header") Probe Rotary
h3(slot="header") Choose probe type
div(slot="body")
p Pick which probe routine to run.
button.pure-button(:class="state['pw'] ? '' : 'load-on'", @click="showProbeDialog('xyz')") Probe XYZ
button.pure-button(:class="state['pw'] ? '' : 'load-on'", @click="showProbeDialog('z')") Probe Z
div(slot="footer")
@@ -46,7 +47,9 @@ script#control-view-template(type="text/x-template")
.control-grid
// ===== JOG =====
.jog-card
// Hidden only while a G-code program is running / paused /
// stopping. Jogging / homing / MDI moves do not hide it.
.jog-card(v-if="!is_program_executing")
.jog-head
.jog-title
| Jog
@@ -89,21 +92,25 @@ script#control-view-template(type="text/x-template")
.fa.fa-arrow-down.ico(style="transform: rotate(-45deg)")
button.jbtn(@click="jog_fn(0, 0, -1, 0)") Z
// Row 4 — W axis (auxcnc) when enabled
// Row 4 — W axis (auxcnc) when enabled.
// W- | W+ | Probe XYZ | Probe Z
// "Home W" lives in the DRO table's actions column on the
// right, so it doesn't need a tile here.
template(v-if="w.enabled")
button.jbtn(@click="aux_jog_incr(-1)", :disabled="!w.enabled")
.fa.fa-arrow-down.ico
span.lbl W
button.jbtn.ghost(@click="aux_home()", :disabled="!w.enabled")
span.lbl Home
span W
button.jbtn(@click="aux_jog_incr(+1)", :disabled="!w.enabled")
.fa.fa-arrow-up.ico
span.lbl W+
button.jbtn(@click="show_probe_dialog=true",
button.jbtn(@click="showProbeDialog('xyz')",
:class="{'load-on': !state['pw']}")
.fa.fa-bullseye.ico
span.lbl Probe
span.lbl Probe XYZ
button.jbtn(@click="showProbeDialog('z')",
:class="{'load-on': !state['pw']}")
.fa.fa-bullseye.ico
span.lbl Probe Z
// Row 4 — A axis (rotary) when no W and rotary is enabled
// (Vue 1 has no v-else-if; we negate w.enabled explicitly.)
@@ -129,16 +136,72 @@ script#control-view-template(type="text/x-template")
.fa.fa-bullseye.ico
span.lbl Probe XYZ
button.jbtn.ghost(@click="zero()", :disabled="!can_set_axis")
.fa.fa-map-marker.ico
.fa.fa-location-dot.ico
span.lbl Zero all
button.jbtn(@click="showProbeDialog('z')",
:class="{'load-on': !state['pw']}")
.fa.fa-bullseye.ico
span.lbl Probe Z
button.jbtn.ghost(@click="home()", :disabled="!is_idle")
button.jbtn.ghost(@click="home()")
.fa.fa-home.ico
span.lbl Home all
// ===== NOW RUNNING (replaces jog grid only while a G-code
// program is actually executing). Jogging is excluded.
.running-panel(v-if="is_program_executing")
.running-top
div
.running-file
.fa.fa-file-code
span(v-if="state.selected")  {{state.selected}}
span(v-else)  {{(mach_state || 'BUSY').toLowerCase()}}
.running-meta
span(v-if="is_running") {{ (mach_state || 'RUNNING').toLowerCase() }}
span(v-if="is_holding") paused
span(v-if="is_holding && pause_reason") · {{pause_reason}}
span(v-if="is_stopping") stopping
span(v-if="toolpath.lines") · line {{state.line || 0 | number}} / {{toolpath.lines | number}}
span(v-if="plan_time_remaining") · ETA {{plan_time_remaining | time}}
.running-pct
| {{((progress || 0) * 100) | fixed 0}}
span %
.running-progress
div(:style="'width:' + ((progress || 0) * 100) + '%'")
.running-stats
.running-stat
.lbl Velocity
.val
unit-value(:value="state.v", precision="2", unit="", iunit="", scale="0.0254")
|  {{metric ? 'm/min' : 'IPM'}}
.running-stat
.lbl Feed
.val
unit-value(:value="state.feed", precision="0", unit="", iunit="")
|  {{metric ? 'mm/min' : 'IPM'}}
.running-stat
.lbl Spindle
.val
| {{(state.speed || 0) | fixed 0}}
span(v-if="state.s != null && !isNaN(state.s)") ({{state.s | fixed 0}})
|  RPM
.running-stat
.lbl Tool
.val T{{state.tool || 0}}
.running-row
// While RUNNING the primary action is Pause; while HOLDING / STOPPING it's Resume.
button.tx-btn.pause(v-if="is_running", @click="pause()")
.fa.fa-pause
span.lbl PAUSE
button.tx-btn.run(v-if="is_holding || is_stopping", @click="unpause()")
.fa.fa-play
span.lbl RESUME
button.tx-btn.stop(@click="stop()")
.fa.fa-stop
span.lbl STOP
button.tx-btn.step(v-if="is_holding", @click="step()")
.fa.fa-forward-step
span.lbl STEP
// ===== DRO + status strip =====
.right-col
@@ -174,11 +237,11 @@ script#control-view-template(type="text/x-template")
button.icon-btn(:disabled="!can_set_axis",
:title=`'Set ${axis.toUpperCase()} axis position.'`,
@click=`show_set_position('${axis}')`)
.fa.fa-cog
.fa.fa-gear
button.icon-btn(:disabled="!can_set_axis",
:title=`'Zero ${axis.toUpperCase()} axis offset.'`,
@click=`zero('${axis}')`)
.fa.fa-map-marker
.fa.fa-location-dot
button.icon-btn(:disabled="!is_idle",
:title=`'Home ${axis.toUpperCase()} axis.'`,
@click=`home('${axis}')`)
@@ -201,9 +264,9 @@ script#control-view-template(type="text/x-template")
|  {{w.tstate}}
.actions-cell
button.icon-btn(disabled, style="visibility:hidden")
.fa.fa-cog
.fa.fa-gear
button.icon-btn(disabled, style="visibility:hidden")
.fa.fa-map-marker
.fa.fa-location-dot
button.icon-btn(:disabled="!w.enabled",
title="Home W axis.", @click="aux_home()")
.fa.fa-home

View File

@@ -6,11 +6,11 @@ script#indicators-template(type="text/x-template")
tr
td
.fa.fa-plus-circle.io
.fa.fa-circle-plus.io
th Hi/+3.3v
th.separator
td
.fa.fa-minus-circle.io
.fa.fa-circle-minus.io
th Lo/Gnd
th.separator
td
@@ -22,7 +22,7 @@ script#indicators-template(type="text/x-template")
th Inactive
th.separator
td
.fa.fa-circle-o.io
.far.fa-circle.io
th Tristated/Disabled
table.inputs
@@ -169,14 +169,14 @@ script#indicators-template(type="text/x-template")
tr
th Motor
th(title="Overtemperature fault"): .fa.fa-thermometer-full
th(title="Overtemperature fault"): .fa.fa-temperature-full
th(title="Overcurrent motor channel A") A #[.fa.fa-bolt]
th(title="Predriver fault motor channel A")
| A #[.fa.fa-exclamation-triangle]
| A #[.fa.fa-triangle-exclamation]
th(title="Overcurrent motor channel B") B #[.fa.fa-bolt]
th(title="Predriver fault motor channel B")
| B #[.fa.fa-exclamation-triangle]
th(title="Driver communication failure"): .fa.fa-handshake-o
| B #[.fa.fa-triangle-exclamation]
th(title="Driver communication failure"): .fa.fa-handshake
th(title="Reset all motor flags")
.fa.fa-eraser(@click="motor_reset()")

View File

@@ -3,7 +3,7 @@ script#path-viewer-template(type="text/x-template")
.path-viewer-toolbar
.tool-button(title="Toggle path view size.",
@click="small = !small", :class="{active: !small}")
.fa.fa-arrows-alt
.fa.fa-up-down-left-right
.tool-button(@click="showTool = !showTool", :class="{active: showTool}",
title="Show/hide tool.")

View File

@@ -82,7 +82,7 @@ script#program-view-template(type="text/x-template")
span STOP
button.action-btn(@click="open_folder", :disabled="!is_ready",
title="Upload a new GCode folder.")
.fa.fa-folder-arrow-up.ico
.fa.fa-folder-plus.ico
span UPLOAD FOLDER
form.gcode-folder-input.file-upload
input#folderInput(type="file", @change="upload_folder",
@@ -126,10 +126,15 @@ script#program-view-template(type="text/x-template")
.fa.fa-arrow-down-wide-short
|  {{files_sortby}}
// Body: gcode listing on the left, 3D viewer on the right
.program-body
// Body: gcode listing on the left, 3D viewer on the right.
// The 3D path-viewer is suppressed when the UI is loaded by
// the Pi's onboard kiosk browser — the VideoCore IV cannot
// run three.js at a usable frame rate. Off-Pi clients still
// see the full split.
.program-body(:class="{'no-preview': is_kiosk}")
gcode-viewer
path-viewer(:toolpath="toolpath", :state="state", :config="config")
path-viewer(v-if="!is_kiosk", :toolpath="toolpath",
:state="state", :config="config")
.progress-bar(v-if="toolpath_progress && toolpath_progress < 1",
title="Simulating GCode to check for errors, calculate ETA and generate 3D view.")

View File

@@ -24,21 +24,35 @@ script#settings-shell-view-template(type="text/x-template")
// Explicit v-if cascade so the inner template swaps reactively
// when sub changes (Vue 1's `<component :is>` does not always
// re-evaluate dynamic strings inside a kept-alive parent).
settings-view-inner(v-if="sub === 'settings'",
// The Svelte settings views read many config keys eagerly on
// attach (settings.units, settings.easy-adapter, motion.*),
// so we gate the inner mount on config_ready.
settings-view-inner(v-if="sub === 'settings' && config_ready",
section="display",
:index="index", :config="config", :template="template", :state="state")
admin-general-view(v-if="sub === 'admin-general'",
settings-view-inner(v-if="sub === 'probing' && config_ready",
section="probing",
:index="index", :config="config", :template="template", :state="state")
admin-network-view(v-if="sub === 'admin-network'",
settings-view-inner(v-if="sub === 'gcode' && config_ready",
section="gcode",
:index="index", :config="config", :template="template", :state="state")
motor-view(v-if="sub === 'motor'",
admin-general-view(v-if="sub === 'admin-general' && config_ready",
:index="index", :config="config", :template="template", :state="state")
tool-view(v-if="sub === 'tool'",
admin-network-view(v-if="sub === 'admin-network' && config_ready",
:index="index", :config="config", :template="template", :state="state")
io-view(v-if="sub === 'io'",
motor-view(v-if="sub === 'motor' && config_ready",
:index="index", :config="config", :template="template", :state="state")
macros-view(v-if="sub === 'macros'",
tool-view(v-if="sub === 'tool' && config_ready",
:index="index", :config="config", :template="template", :state="state")
help-view(v-if="sub === 'help'",
io-view(v-if="sub === 'io' && config_ready",
:index="index", :config="config", :template="template", :state="state")
cheat-sheet-view(v-if="sub === 'cheat-sheet'",
w-axis-view(v-if="sub === 'w-axis' && config_ready",
:index="index", :config="config", :template="template", :state="state")
macros-view(v-if="sub === 'macros' && config_ready",
:index="index", :config="config", :template="template", :state="state")
help-view(v-if="sub === 'help' && config_ready",
:index="index", :config="config", :template="template", :state="state")
cheat-sheet-view(v-if="sub === 'cheat-sheet' && config_ready",
:index="index", :config="config", :template="template", :state="state")
.settings-loading(v-if="!config_ready")
| Loading configuration…

View File

@@ -433,4 +433,4 @@ script#tool-view-template(type="text/x-template")
| Other settings according to the
|
a(href="https://buildbotics.com/upload/vfd/stepperonline-v70.pdf",
target="_blank") Stepper Online V70 VFD manual
target="_blank") Stepper Online V70 VFD manual

View File

@@ -0,0 +1,4 @@
script#w-axis-view-template(type="text/x-template")
#w-axis-page
h1 W Axis (auxcnc)
#w-axis-mount