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 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