<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
<title>Tiles Grid + PHP Gallery + Objects + Lines + Attributes</title>
<script>
// Cache timestamp for all resources
const timestamp = Date.now();
// Apply cache-busting to CSS
document.write(`<link rel="stylesheet" href="styles.css?v=${timestamp}">`);
</script>
</head>
<body>
<div class="topbar">
<button id="settingsBtn" title="Settings">โ๏ธ</button>
<button id="imagesBtn" title="Images">๐ผ๏ธ</button>
<button id="objectViewBtn" title="Object View">๐๏ธ</button>
<button id="resetBtn" title="Reset view">๐</button>
</div>
<!-- Settings panel -->
<div class="panel" id="settingsPanel">
<div class="settings-track">
<div class="stepper" data-key="tileWidth"><label>tileWidth</label>
<div class="stepper-controls"><button>-</button><input type="number" value="16"><button>+</button></div>
</div>
<div class="stepper" data-key="tileHeight"><label>tileHeight</label>
<div class="stepper-controls"><button>-</button><input type="number" value="16"><button>+</button></div>
</div>
<div class="stepper" data-key="xOffset"><label>xOffset</label>
<div class="stepper-controls"><button>-</button><input type="number" value="0"><button>+</button></div>
</div>
<div class="stepper" data-key="yOffset"><label>yOffset</label>
<div class="stepper-controls"><button>-</button><input type="number" value="0"><button>+</button></div>
</div>
<div class="stepper" data-key="Hspacing"><label>Hspacing</label>
<div class="stepper-controls"><button>-</button><input type="number" value="0"><button>+</button></div>
</div>
<div class="stepper" data-key="Vspacing"><label>Vspacing</label>
<div class="stepper-controls"><button>-</button><input type="number" value="0"><button>+</button></div>
</div>
</div>
</div>
<!-- Images panel (PHP-driven) -->
<div class="panel" id="imagesPanel">
<div class="folder-bar">
<strong style="margin-right:.5rem">๐</strong>
<div class="crumbs" id="crumbs"></div>
<div style="flex:1"></div>
<button id="goUpBtn" title="Up one level" style="background:none;border:1px solid #2a2a2a;border-radius:.4rem;padding:.35rem .6rem;color:var(--ink)">โฌ๏ธ Up</button>
<button id="refreshBtn" title="Refresh" style="margin-left:.4rem;background:none;border:1px solid #2a2a2a;border-radius:.4rem;padding:.35rem .6rem;color:var(--ink)">๐</button>
</div>
<div class="folders-track" id="foldersTrack"></div>
<div class="empty-hint" id="emptyFolders" hidden>No folders here.</div>
<div class="gallery-track" id="galleryTrack"></div>
<div class="empty-hint" id="emptyImages" hidden>No images in this folder.</div>
</div>
<div class="content">
<!-- Objects bar -->
<div class="objects" id="objectsBar">
<div id="objectPills"></div>
<div class="controls">
<button id="addObjectBtn">โ New Object</button>
<button id="renameObjectBtn">โ๏ธ Rename</button>
<button id="removeObjectBtn">๐๏ธ Delete</button>
</div>
</div>
<!-- Lines (for active object) -->
<div class="lines" id="linesBar">
<div id="linePills"></div>
<div class="controls">
<button id="addLineBtn">โ Add Line</button>
<button id="renameLineBtn">โ๏ธ Rename</button>
<button id="removeLineBtn">๐๏ธ Remove</button>
<button id="clearLineBtn">๐งน Clear Line</button>
</div>
</div>
<!-- Tank (active line) -->
<div class="tank" id="tankBar">
<div class="count" id="tankCount">0 items</div>
<div class="tank-strip" id="tankStrip" title="Captured tiles for the selected line appear here"></div>
</div>
<div class="meta" id="meta">Open an image, then tap grid tiles to add thumbnails to the selected line.</div>
<div class="stage" id="stage">
<div class="viewport" id="viewport">
<div class="img-layer" id="imgLayer"></div>
<div class="grid" id="grid"></div>
</div>
</div>
</div>
<!-- Full-screen Object View -->
<div class="overlay" id="objectOverlay" aria-hidden="true">
<div class="ov-wrap">
<div class="ov-head">
<h2 id="ovTitle">Object</h2>
<button id="closeOverlayBtn">โ Close</button>
</div>
<div class="ov-body" id="ovBody"></div>
</div>
</div>
<script>
// Cache timestamp for cache busting (already defined above for CSS)
if (typeof timestamp === 'undefined') {
const timestamp = Date.now();
}
// Global error handler
window.addEventListener('error', (e) => {
// Silent error logging - could add console.log here if needed
});
// Script loader with caching control
function loadScript(src, callback) {
const script = document.createElement('script');
script.src = `${src}?v=${timestamp}`;
script.onload = callback;
script.onerror = () => {
// Silent error - could add console.log here if needed
};
document.head.appendChild(script);
}
// Load scripts in sequence with verification
function initializeApp() {
loadScript('core.js', () => {
if (typeof initializeCore !== 'function') return;
loadScript('workspace.js', () => {
if (typeof initializeWorkspace !== 'function') return;
loadScript('attributes.js', () => {
if (typeof initializeAttributes !== 'function') return;
loadScript('gallery.js', () => {
if (typeof initializeGallery !== 'function') return;
// All scripts loaded - initialize
try {
initializeCore();
initializeWorkspace();
initializeAttributes();
initializeGallery();
} catch (error) {
alert(`Initialization failed: ${error.message}`);
}
});
});
});
});
}
// Start when DOM is ready
document.addEventListener('DOMContentLoaded', initializeApp);
</script>
</body>
</html>