Files
shopdb/tv-dashboard/index.html
cproudlock 08ffa4ba36 Add displaylocations, location/inspection migrations, UI refinements
- New displaylocations.asp (production location listing)
- 3 new SQL migrations: inspection machine type, location relationship
  types, pctype inspection update
- displaymachine.asp / printbadge.asp substantial rework
- editmachine/editpc/savemachineedit: ~50 line additions each
- Dashboard index.html + tv-dashboard tweaks
- .gitignore: block database-backup-*.sql, *.bak, *.pdf

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:06:28 -04:00

184 lines
5.6 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>West Jefferson - Display</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #000;
margin: 0;
padding: 0;
overflow: hidden;
height: 100vh;
width: 100vw;
}
.slideshow-container {
position: relative;
width: 100vw;
height: 100vh;
background: #000;
}
.slide {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: opacity 1s ease-in-out;
display: flex;
align-items: center;
justify-content: center;
}
.slide.active {
opacity: 1;
}
.slide img {
width: 100%;
height: 100%;
object-fit: contain;
}
.progress-bar {
position: fixed;
bottom: 0;
left: 0;
height: 4px;
background: #4181ff;
transition: width linear;
z-index: 100;
}
.error-message {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
color: #fff;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 24px;
}
.error-message h2 {
color: #ff4444;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="slideshow-container" id="slideshow"></div>
<div class="progress-bar" id="progressBar"></div>
<script>
const INTERVAL = 10; // seconds between slides
let slides = [];
let currentSlide = 0;
let slideTimer = null;
// Fetch slides from API
async function fetchSlides() {
try {
const response = await fetch('apislides.asp');
if (!response.ok) throw new Error('API error');
const data = await response.json();
if (data.success && data.slides && data.slides.length > 0) {
updateSlides(data.slides, data.basepath);
} else {
showError(data.message || 'No slides found');
}
} catch (error) {
console.error('Error fetching slides:', error);
showError('Unable to load slides');
}
}
// Update slides in DOM
function updateSlides(newSlides, basepath) {
const slideshow = document.getElementById('slideshow');
const currentSlideNames = slides.map(s => s.filename);
const newSlideNames = newSlides.map(s => s.filename);
// Check if slides changed
if (JSON.stringify(currentSlideNames) !== JSON.stringify(newSlideNames)) {
slideshow.innerHTML = '';
slides = [];
newSlides.forEach((slide, index) => {
const div = document.createElement('div');
div.className = 'slide' + (index === 0 ? ' active' : '');
const img = document.createElement('img');
img.src = basepath + encodeURIComponent(slide.filename);
div.appendChild(img);
slideshow.appendChild(div);
slides.push({ element: div, filename: slide.filename });
});
currentSlide = 0;
if (slides.length > 1) startSlideshow();
}
}
function showError(message) {
document.getElementById('slideshow').innerHTML =
'<div class="error-message"><h2>Display Error</h2><p>' + message + '</p></div>';
// Clear slides so the next successful fetch always re-renders
slides = [];
currentSlide = 0;
if (slideTimer) { clearTimeout(slideTimer); slideTimer = null; }
}
function startSlideshow() {
if (slideTimer) clearTimeout(slideTimer);
scheduleNextSlide();
}
function scheduleNextSlide() {
const progressBar = document.getElementById('progressBar');
progressBar.style.width = '0%';
progressBar.style.transition = 'none';
setTimeout(() => {
progressBar.style.transition = 'width ' + INTERVAL + 's linear';
progressBar.style.width = '100%';
}, 50);
slideTimer = setTimeout(() => {
nextSlide();
scheduleNextSlide();
}, INTERVAL * 1000);
}
function nextSlide() {
if (slides.length === 0) return;
slides[currentSlide].element.classList.remove('active');
currentSlide = (currentSlide + 1) % slides.length;
slides[currentSlide].element.classList.add('active');
}
// Start
fetchSlides();
// Refresh every 60 seconds to pick up new slides
setInterval(fetchSlides, 60000);
</script>
</body>
</html>