- 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
265 lines
9.9 KiB
Plaintext
265 lines
9.9 KiB
Plaintext
doctype html
|
|
html(lang="en")
|
|
head
|
|
meta(charset="utf-8")
|
|
meta(name="viewport", content="width=device-width, initial-scale=1.0")
|
|
|
|
title Onefinity CNC - Web interface
|
|
|
|
|
|
style: include ../static/css/pure-min.css
|
|
|
|
style: include ../static/css/fa6.min.css
|
|
style: include ../static/css/Audiowide.css
|
|
style: include ../static/css/clusterize.css
|
|
style: include ../svelte-components/node_modules/svelte-material-ui/bare.css
|
|
style: include ../../build/http/svelte-components/smui.css
|
|
style: include ../../build/http/svelte-components/style.css
|
|
style: include:stylus ../stylus/style.styl
|
|
|
|
body(v-cloak)
|
|
// Tablet (kiosk) mode — pins the .app-shell to 1920x1080 and
|
|
// scales it to fit the actual viewport so the UI always looks
|
|
// exactly like the 10.8" 1920x1080 portable monitor.
|
|
//
|
|
// Toggle: ?tablet=1 to enable
|
|
// ?tablet=0 to disable
|
|
// Sticky in localStorage; once set, no querystring is needed.
|
|
script.
|
|
(function () {
|
|
try {
|
|
var p = new URLSearchParams(location.search);
|
|
if (p.has("tablet")) {
|
|
var on = p.get("tablet") !== "0" && p.get("tablet") !== "false";
|
|
localStorage.setItem("ui-tablet-mode", on ? "1" : "0");
|
|
}
|
|
if (localStorage.getItem("ui-tablet-mode") === "1") {
|
|
document.documentElement.classList.add("tablet-mode");
|
|
}
|
|
function fit() {
|
|
if (!document.documentElement.classList.contains("tablet-mode")) return;
|
|
var s = Math.min(window.innerWidth / 1920, window.innerHeight / 1080);
|
|
document.documentElement.style.setProperty("--tablet-scale", s);
|
|
}
|
|
fit();
|
|
window.addEventListener("resize", fit);
|
|
|
|
// Kiosk mode: when the UI is loaded by the controller's
|
|
// own onboard browser (Chromium pointing at localhost on
|
|
// the Pi 3B at 1366x768), apply a tighter layout that
|
|
// packs the V09 UI into the smaller, slower display.
|
|
// Override with ?kiosk=0 to force the desktop layout.
|
|
if (p.has("kiosk")) {
|
|
var k = p.get("kiosk") !== "0" && p.get("kiosk") !== "false";
|
|
localStorage.setItem("ui-kiosk-mode", k ? "1" : "0");
|
|
}
|
|
var stored = localStorage.getItem("ui-kiosk-mode");
|
|
var auto = location.hostname === "localhost"
|
|
|| location.hostname === "127.0.0.1"
|
|
|| location.hostname === "::1";
|
|
if (stored === "1" || (stored !== "0" && auto)) {
|
|
document.documentElement.classList.add("kiosk-mode");
|
|
}
|
|
} catch (_e) {}
|
|
})();
|
|
|
|
#svelte-dialog-host
|
|
|
|
#overlay(v-if="status != 'connected'")
|
|
span {{status}}
|
|
|
|
.app-shell
|
|
header.app-head
|
|
.brand-blk
|
|
.brand-logo
|
|
.brand-name ONEFINITY
|
|
|
|
nav.tabs-host(role="tablist")
|
|
a.ktab(:class="{active: top_tab === 'control'}", href="#control",
|
|
title="Jog, DRO, macros")
|
|
.fa.fa-gamepad
|
|
span Control
|
|
a.ktab(:class="{active: top_tab === 'program'}", href="#program",
|
|
title="Run programs, files, toolpath preview")
|
|
.fa.fa-list-ol
|
|
span Program
|
|
a.ktab(:class="{active: top_tab === 'console'}", href="#console",
|
|
title="MDI, messages, indicators")
|
|
.fa.fa-terminal
|
|
span Console
|
|
span.ktab-badge(v-if="messages_count") {{messages_count}}
|
|
a.ktab(:class="{active: top_tab === 'settings'}", href="#settings",
|
|
title="Configuration, network, macros")
|
|
.fa.fa-sliders
|
|
span Settings
|
|
|
|
.head-spacer
|
|
|
|
.sys-btn(@click.stop="toggle_sys_popover", :class="{open: sys_open}")
|
|
span.pip(:class="sys_class")
|
|
span.sys-text {{sys_summary}}
|
|
.fa.fa-chevron-down
|
|
|
|
.pi-temp-warning(v-if="80 <= state.rpi_temp",
|
|
title="Raspberry Pi temperature too high.")
|
|
.fa.fa-temperature-full
|
|
|
|
span.state-badge(:class="state_class", :title="mach_state_full")
|
|
span.dot
|
|
span {{state_label}}
|
|
|
|
.estop(:class="{active: state.es}")
|
|
estop(@click="estop")
|
|
|
|
// System popover (chip-soup destination)
|
|
.sys-popover(v-if="sys_open", @click.stop="")
|
|
.sp-row
|
|
.sp-icon: .fa.fa-microchip
|
|
.sp-text
|
|
.sp-label Firmware
|
|
.sp-val v{{config.full_version}}
|
|
a.sp-act(v-if="show_upgrade()", href="#admin-general")
|
|
| Upgrade to v{{latestVersion}}
|
|
.fa.fa-circle-exclamation.upgrade-attention
|
|
.sp-row
|
|
.sp-icon: .fa.fa-network-wired
|
|
.sp-text
|
|
.sp-label IP Address
|
|
.sp-val {{config.ip}}
|
|
.sp-row
|
|
.sp-icon: .fa.fa-wifi(:class="{'sp-warn': config.wifiName === 'not connected'}")
|
|
.sp-text
|
|
.sp-label WiFi
|
|
.sp-val {{config.wifiName}}
|
|
a.sp-act(href="#admin-network", @click="sys_open=false") Configure
|
|
.sp-row(v-if="enable_rotary")
|
|
.sp-icon: img(src="/images/rotary.svg", alt="rotary")
|
|
.sp-text
|
|
.sp-label Rotary
|
|
.sp-val {{is_rotary_active ? 'Active' : 'Inactive'}}
|
|
button.sp-act(@click="showSwitchRotaryModeDialog")
|
|
| {{is_rotary_active ? 'Disable' : 'Enable'}}
|
|
.sp-row(v-if="is_easy_adapter_active")
|
|
.sp-icon: .fa.fa-puzzle-piece
|
|
.sp-text
|
|
.sp-label Easy Adapter
|
|
.sp-val Active
|
|
.sp-row.video-row
|
|
.sp-icon: .fa.fa-video
|
|
.sp-text
|
|
.sp-label Camera
|
|
.sp-val {{has_camera ? 'Live' : 'Plug camera into USB'}}
|
|
.sp-act(v-if="has_camera", @click="toggle_video")
|
|
| {{video_size === 'small' ? 'Enlarge' : 'Shrink'}}
|
|
.video(v-if="sys_open && has_camera", title="Camera feed",
|
|
@click="toggle_video", @contextmenu="toggle_crosshair",
|
|
:class="video_size")
|
|
.crosshair(v-if="crosshair")
|
|
.vertical
|
|
.horizontal
|
|
.box
|
|
img(src="/api/video", @error="has_camera=false")
|
|
.sp-foot
|
|
button.sp-shutdown(@click="showShutdownDialog")
|
|
.fa.fa-power-off
|
|
| Shutdown
|
|
button.sp-save(:disabled="!modified", @click="save")
|
|
.fa.fa-save
|
|
| Save{{modified ? '*' : ''}}
|
|
|
|
// Routed view. We keep instances alive across tab swaps so:
|
|
// - The Program tab's WebGL <path-viewer> canvas does not
|
|
// get destroyed and recreated each time (which caused a
|
|
// dark flash as the GL context cleared the new canvas
|
|
// before its first frame).
|
|
// - The Program tab's clusterize.js gcode list does not
|
|
// re-virtualize from scratch on every visit.
|
|
// - The Settings shell's child Svelte components stay
|
|
// mounted, preserving any in-flight form state.
|
|
// The settings-shell handles its own inner v-if cascade so
|
|
// the Vue 1 reactivity quirk that motivated removing
|
|
// keep-alive earlier no longer applies here.
|
|
.app-body
|
|
component(:is="currentView + '-view'", :index="index",
|
|
:config="config", :template="template", :state="state",
|
|
:sub-tab="sub_tab", keep-alive)
|
|
|
|
message.error-message(:show.sync="errorShow")
|
|
div(slot="header")
|
|
.estop(:class="{active: state.es}"): estop(@click="estop")
|
|
h3 ERROR: {{errorMessage}}
|
|
|
|
div(slot="body")
|
|
console
|
|
|
|
button.pure-button(@click="block_error_dialog")
|
|
.fa.fa-ban
|
|
| Stop
|
|
label showing errors for
|
|
input(style="width: 50px", v-model="errorTimeout", number)
|
|
label seconds.
|
|
|
|
div(slot="footer")
|
|
button.pure-button.pure-button-primary(@click="errorShow = false") OK
|
|
|
|
message(:show.sync="confirmUpgrade")
|
|
h3(slot="header") Upgrade Firmware?
|
|
div(slot="body")
|
|
p
|
|
| Are you sure you want to upgrade the firmware to version
|
|
| {{latestVersion}}?
|
|
|
|
div(slot="footer")
|
|
button.pure-button(@click="confirmUpgrade=false") Cancel
|
|
button.pure-button.pure-button-primary(@click="upgrade_confirmed")
|
|
| Upgrade
|
|
|
|
message(:show.sync="confirmUpload")
|
|
h3(slot="header") Upload Firmware?
|
|
div(slot="body")
|
|
p Are you sure you want to upload firmware #[em {{firmwareName}}]?
|
|
|
|
div(slot="footer")
|
|
button.pure-button(@click="confirmUpload=false") Cancel
|
|
button.pure-button.pure-button-primary(@click="upload_confirmed")
|
|
| Upload
|
|
|
|
message(:show.sync="firmwareUpgrading")
|
|
h3(slot="header") Firmware upgrading
|
|
div(slot="body")
|
|
h3 Please wait...
|
|
p This process should take less than 5 minutes. If it takes longer than this, please restart the controller and try via USB.
|
|
div(slot="footer")
|
|
|
|
message(v-if="popupMessages.length", show=true)
|
|
h3(slot="header") GCode message
|
|
|
|
div(slot="body")
|
|
ul
|
|
li(v-for="msg in popupMessages", track-by="$index") {{msg}}
|
|
|
|
div(slot="footer")
|
|
button.pure-button.button-success(v-if="state.xx != 'HOLDING'",
|
|
@click="close_messages('ok')") OK
|
|
|
|
div(v-if="state.xx == 'HOLDING'")
|
|
button.pure-button(@click="close_messages('stop')")
|
|
| Stop
|
|
.fa.fa-stop
|
|
|
|
button.pure-button(@click="close_messages('continue')")
|
|
| Continue
|
|
.fa.fa-play
|
|
|
|
#templates: include ../../build/templates.pug
|
|
iframe#download-target(style="display:none")
|
|
|
|
|
|
script: include ../static/js/vue.js
|
|
script: include ../static/js/sockjs.min.js
|
|
script: include ../static/js/clusterize.min.js
|
|
script: include ../static/js/three.min.js
|
|
script: include:browserify ../js/main.js
|
|
script: include ../../build/http/svelte-components/index.js
|
|
script: include ../static/js/ui.js
|