shopfloor dashboard: fit-to-viewport scaling for TV kiosks
The board was a fixed-pixel layout with an internal overflow-y scroll, so on a TV (no scrolling) content past the fold was unreachable. Wrap it in a fixed 1920-wide surface and scale it to fill the viewport (ResizeObserver + resize), so the whole board is visible edge-to-edge at any resolution. Drop the .dashboard-content max-height/overflow scroll.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<div class="shopfloor-dashboard">
|
||||
<div class="dash-fit" ref="fitEl">
|
||||
<header class="dashboard-header">
|
||||
<div class="logo-container">
|
||||
<img :src="siteLogo" alt="Site logo" class="logo" />
|
||||
@@ -179,11 +180,12 @@
|
||||
<footer class="dashboard-footer">
|
||||
Auto-refreshes every 30 seconds
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { notificationsApi, businessUnitsApi, dashboardDefaultsApi } from '@/api'
|
||||
import { getFacilityName, getSiteLogo, getServicenowUrls } from '@/utils/siteSettings'
|
||||
import { withBase } from '@/utils/basePath'
|
||||
@@ -204,6 +206,20 @@ let refreshInterval = null
|
||||
let recognitionInterval = null
|
||||
let recertPageInterval = null
|
||||
|
||||
// Fit-to-viewport: the board is a fixed 1920-wide design; scale the whole thing
|
||||
// to fill the screen so a TV shows everything with no scrolling, at any size.
|
||||
const fitEl = ref(null)
|
||||
let resizeObserver = null
|
||||
function fitToScreen() {
|
||||
const el = fitEl.value
|
||||
if (!el) return
|
||||
const w = el.offsetWidth || 1
|
||||
const h = el.offsetHeight || 1
|
||||
const scale = Math.min(window.innerWidth / w, window.innerHeight / h)
|
||||
el.style.transform = `scale(${scale})`
|
||||
el.style.left = `${Math.max(0, (window.innerWidth - w * scale) / 2)}px`
|
||||
}
|
||||
|
||||
// The board groups cards by each type's configured display style, so any custom
|
||||
// type set to carousel/grid/banner renders that way - not just the built-ins.
|
||||
const SPECIAL_STYLES = ['carousel', 'grid', 'banner']
|
||||
@@ -318,12 +334,22 @@ onMounted(async () => {
|
||||
currentRecertPage.value = (currentRecertPage.value + 1) % recertPageCount.value
|
||||
}
|
||||
}, 7000)
|
||||
|
||||
// Scale to fit once rendered, and re-fit whenever the content or window
|
||||
// changes size (new data, banner cycling, resolution change).
|
||||
await nextTick()
|
||||
fitToScreen()
|
||||
resizeObserver = new ResizeObserver(() => fitToScreen())
|
||||
if (fitEl.value) resizeObserver.observe(fitEl.value)
|
||||
window.addEventListener('resize', fitToScreen)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (refreshInterval) clearInterval(refreshInterval)
|
||||
if (recognitionInterval) clearInterval(recognitionInterval)
|
||||
if (recertPageInterval) clearInterval(recertPageInterval)
|
||||
resizeObserver?.disconnect()
|
||||
window.removeEventListener('resize', fitToScreen)
|
||||
})
|
||||
|
||||
async function loadData() {
|
||||
@@ -417,13 +443,25 @@ function handlePhotoError(e) {
|
||||
|
||||
<style scoped>
|
||||
.shopfloor-dashboard {
|
||||
min-height: 100vh;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
background: #00003d;
|
||||
color: #fff;
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Fixed 1920-wide design surface; JS scales it to fill the viewport (TV) so
|
||||
the whole board is visible with no scrolling. */
|
||||
.dash-fit {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 1920px;
|
||||
transform-origin: top left;
|
||||
}
|
||||
|
||||
.dashboard-header {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
@@ -485,8 +523,6 @@ function handlePhotoError(e) {
|
||||
|
||||
.dashboard-content {
|
||||
padding: 20px 40px;
|
||||
max-height: calc(100vh - 180px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
|
||||
Reference in New Issue
Block a user