{"id":3873,"date":"2026-08-07T16:07:16","date_gmt":"2026-08-07T08:07:16","guid":{"rendered":"https:\/\/www.ukm.my\/minggudigital\/?page_id=3873"},"modified":"2026-10-16T11:37:30","modified_gmt":"2026-10-16T03:37:30","slug":"pameran","status":"publish","type":"page","link":"https:\/\/www.ukm.my\/minggudigital\/pameran\/","title":{"rendered":"PAMERAN"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"3873\" class=\"elementor elementor-3873\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9f7aaab e-flex e-con-boxed e-con e-parent\" data-id=\"9f7aaab\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-f5a72e1 e-con-full e-flex e-con e-child\" data-id=\"f5a72e1\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-f550662 e-con-full e-flex e-con e-child\" data-id=\"f550662\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-cc8175f elementor-widget elementor-widget-heading\" data-id=\"cc8175f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\">Pameran<\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-e7cc91e e-con-full e-flex e-con e-child\" data-id=\"e7cc91e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-10d077c elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"10d077c\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b66de80\" data-id=\"b66de80\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-75d2250 elementor-widget elementor-widget-html\" data-id=\"75d2250\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"ms\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Pelan Lantai Interaktif Pameran<\/title>\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n    <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@300;400;500;600;700&display=swap&__ncforminfo=hSzOe-Mhl_uXh98GIIIBfWyPz63TXE6t68k9vGbfmybUAWgiuNlKEswJMAdx9YU0e4QAFzFhb7YVj7ALsQB5msy36Sn6s4nH&__ncforminfo=axWzqU7zQqdT3I40p_8iSwrJVbM-uoS4xvVNU7BQMQlrlgOlhSjlXthlKXjO9vbdf1Sz8oOzJrwAYOszzANoHbDg9qYRJLVgx9XyA15Z2Tk=\" rel=\"stylesheet\">\n    <script src=\"https:\/\/unpkg.com\/lucide@latest\"><\/script>\n    \n    <style>\n        body {\n            font-family: 'Inter', sans-serif;\n            background-color: #ffffff;\n        }\n        \n        \/* Custom scrollbar styling *\/\n        ::-webkit-scrollbar {\n            width: 8px;\n            height: 8px;\n        }\n        ::-webkit-scrollbar-track {\n            background: #f1f1f1;\n        }\n        ::-webkit-scrollbar-thumb {\n            background: #cbd5e1;\n            border-radius: 4px;\n        }\n        ::-webkit-scrollbar-thumb:hover {\n            background: #94a3b8;\n        }\n\n        .hotspot {\n            position: absolute;\n            cursor: pointer;\n            transition: all 0.2s ease-in-out;\n            border-radius: 4px;\n            z-index: 10;\n        }\n\n        .hotspot:hover {\n            background-color: rgba(59, 130, 246, 0.3);\n            outline: 2px solid #3b82f6;\n            box-shadow: 0 0 12px rgba(59, 130, 246, 0.5);\n        }\n\n        .hotspot.active {\n            background-color: rgba(37, 99, 235, 0.4);\n            outline: 2px solid #1d4ed8;\n            box-shadow: 0 0 16px rgba(29, 78, 216, 0.7);\n        }\n\n        \/* Tooltip Thumbnail Popup *\/\n        #thumbnail-popover {\n            pointer-events: auto;\n            transition: opacity 0.15s ease, transform 0.15s ease;\n            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.2), 0 8px 10px -6px rgba(0, 0, 0, 0.1);\n        }\n    <\/style>\n<\/head>\n<body class=\"bg-white text-slate-800 min-h-screen flex flex-col\">\n\n    <header class=\"border-b border-slate-200 bg-white sticky top-0 z-30 shadow-sm\">\n        <div class=\"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-3 flex flex-wrap items-center justify-between gap-4\">\n            <div class=\"flex items-center space-x-3\">\n                <div class=\"p-2.5 bg-gradient-to-tr from-cyan-500 via-blue-600 to-purple-600 text-white rounded-2xl shadow-sm flex items-center justify-center\">\n                    <i data-lucide=\"map-pin\" class=\"w-6 h-6\"><\/i>\n                <\/div>\n                <div>\n                    <h1 class=\"text-xl font-bold text-slate-900 leading-tight\">Pelan Lantai Interaktif Pameran<\/h1>\n                    <p class=\"text-xs text-slate-500\">Halakan kursor pada label untuk pratonton thumbnail & klik untuk imej penuh.<\/p>\n                <\/div>\n            <\/div>\n\n            <!-- Search \/ Quick Filter -->\n            <div class=\"relative min-w-[240px] sm:min-w-[300px]\">\n                <i data-lucide=\"search\" class=\"w-4 h-4 absolute left-3 top-1\/2 -translate-y-1\/2 text-slate-400\"><\/i>\n                <input type=\"text\" id=\"search-input\" placeholder=\"Cari label (cth: FTSM, IVI, PTSL)...\" \n                       class=\"w-full pl-9 pr-4 py-2 text-sm border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all\"\n                       oninput=\"handleSearch(this.value)\">\n            <\/div>\n        <\/div>\n    <\/header>\n\n    <main class=\"flex-1 max-w-7xl w-full mx-auto p-4 sm:p-6 lg:p-8 flex flex-col gap-6\">\n        \n        <!-- Floorplan Map Area -->\n        <div class=\"w-full flex flex-col items-center\">\n            <div class=\"bg-slate-50 border border-slate-200 rounded-2xl p-2 sm:p-4 w-full flex justify-center items-center relative overflow-hidden shadow-inner\">\n                \n                <!-- Floor plan wrapper with aspect ratio preservation -->\n                <div id=\"map-container\" class=\"relative w-full max-w-[1000px] select-none\">\n                    <!-- Base Floorplan Image -->\n                    <img decoding=\"async\" id=\"floorplan-img\" \n                         src=\"https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/pelan-lantai_01.jpg\" \n                         alt=\"Pelan Lantai\" \n                         class=\"w-full h-auto block rounded-lg shadow-sm\"\n                         onerror=\"handleFloorplanError(this)\">\n\n                    <!-- Hotspots overlay will be generated dynamically here -->\n                    <div id=\"hotspots-layer\" class=\"absolute inset-0\"><\/div>\n                <\/div>\n\n            <\/div>\n        <\/div>\n\n        <!-- Directory \/ List Area below Floorplan -->\n        <section class=\"w-full bg-white border border-slate-200 rounded-2xl p-4 sm:p-6 flex flex-col shadow-sm\">\n            <div class=\"flex items-center justify-between pb-3 border-b border-slate-100 mb-4\">\n                <h2 class=\"font-semibold text-slate-800 text-sm sm:text-base flex items-center gap-2\">\n                    <i data-lucide=\"list\" class=\"w-4 h-4 sm:w-5 sm:h-5 text-blue-600\"><\/i>\n                    Senarai Label & Lokasi\n                <\/h2>\n            <\/div>\n\n            <!-- List items arranged in 2 columns for medium & large screens, 1 column for mobile -->\n            <!--<div id=\"directory-list\" class=\"grid grid-cols-1 md:grid-cols-2 gap-2.5\">-->\n                <div id=\"directory-list\" class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3\">\n                <!-- Directory items populated via JavaScript -->\n            <\/div>\n        <\/section>\n\n    <\/main>\n\n    <!-- Thumbnail Popover -->\n    <div id=\"thumbnail-popover\" class=\"fixed hidden z-50 bg-white border border-slate-200 rounded-xl p-3 w-64 shadow-2xl transition-opacity duration-200 cursor-pointer group\" onclick=\"openModalFromPopover()\">\n        <div class=\"flex items-center justify-between mb-2\">\n            <span id=\"popover-title\" class=\"font-bold text-sm text-slate-800 truncate\"><\/span>\n            <span class=\"text-[10px] bg-blue-100 text-blue-700 px-1.5 py-0.5 rounded font-semibold uppercase\">Klik Imej<\/span>\n        <\/div>\n        \n        <!-- Thumbnail image container -->\n        <div class=\"w-full h-36 bg-slate-100 rounded-lg overflow-hidden border border-slate-200 relative flex items-center justify-center group-hover:border-blue-400 transition-colors\">\n            <img decoding=\"async\" id=\"popover-img\" src=\"\" alt=\"Thumbnail\" class=\"w-full h-full object-contain p-1\">\n            <div class=\"absolute inset-0 bg-blue-900\/10 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center\">\n                <span class=\"bg-slate-900\/80 text-white text-xs px-2.5 py-1 rounded-full flex items-center gap-1 shadow\">\n                    <i data-lucide=\"maximize-2\" class=\"w-3 h-3\"><\/i> Besarkan\n                <\/span>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <!-- Image Modal -->\n    <div id=\"image-modal\" class=\"fixed inset-0 z-50 hidden bg-slate-900\/80 backdrop-blur-sm flex items-center justify-center p-4 sm:p-6 opacity-0 transition-opacity duration-300\">\n        <div class=\"bg-white rounded-2xl max-w-5xl w-full max-h-[92vh] flex flex-col overflow-hidden shadow-2xl transform scale-95 transition-transform duration-300\" id=\"modal-card\">\n            \n            <!-- Modal Header -->\n            <div class=\"px-6 py-4 border-b border-slate-200 flex items-center justify-between bg-slate-50 select-none\">\n                <div class=\"flex items-center space-x-3\">\n                    <div class=\"p-2 bg-blue-100 text-blue-600 rounded-lg\">\n                        <i data-lucide=\"zoom-in\" class=\"w-5 h-5\"><\/i>\n                    <\/div>\n                    <div>\n                        <h3 id=\"modal-title\" class=\"text-lg font-bold text-slate-900\"><\/h3>\n                        <p id=\"modal-description\" class=\"text-xs text-slate-500\"><\/p>\n                    <\/div>\n                <\/div>\n                \n                <button onclick=\"closeModal()\" class=\"p-2 text-slate-400 hover:text-slate-600 hover:bg-slate-200\/60 rounded-full transition-colors\">\n                    <i data-lucide=\"x\" class=\"w-6 h-6\"><\/i>\n                <\/button>\n            <\/div>\n\n            <!-- Modal Image Body with Zoom & Pan Container -->\n            <div id=\"modal-img-container\" class=\"flex-1 p-4 bg-slate-900\/10 overflow-hidden relative flex items-center justify-center min-h-[350px] max-h-[72vh] cursor-grab active:cursor-grabbing select-none\">\n                <div id=\"modal-zoom-wrapper\" class=\"transition-transform duration-100 ease-out flex items-center justify-center w-full h-full\">\n                    <img decoding=\"async\" id=\"modal-img\" src=\"\" alt=\"Imej Penuh\" class=\"max-w-full max-h-[65vh] object-contain rounded-lg shadow-md border border-slate-200 pointer-events-none\">\n                <\/div>\n                \n                <!-- Zoom Percentage Indicator Badge -->\n                <div class=\"absolute bottom-4 left-4 bg-slate-900\/75 backdrop-blur text-white text-xs px-3 py-1.5 rounded-full font-mono shadow border border-white\/10 pointer-events-none\" id=\"zoom-badge\">\n                    100%\n                <\/div>\n            <\/div>\n\n            <!-- Modal Footer (Zoom Toolbar Controls) -->\n            <div class=\"px-6 py-3 border-t border-slate-200 bg-white flex items-center justify-center gap-3\">\n                <button onclick=\"zoomImage(-0.25)\" title=\"Zum Keluar\" class=\"p-2 bg-slate-100 text-slate-700 hover:bg-blue-50 hover:text-blue-600 border border-slate-200 rounded-lg transition-colors flex items-center justify-center\">\n                    <i data-lucide=\"zoom-out\" class=\"w-4 h-4\"><\/i>\n                <\/button>\n                <button onclick=\"resetZoomImage()\" title=\"Set Semula Saiz\" class=\"px-3 py-1.5 bg-slate-100 text-slate-700 hover:bg-blue-50 hover:text-blue-600 border border-slate-200 rounded-lg transition-colors text-xs font-semibold\">\n                    Set Semula (100%)\n                <\/button>\n                <button onclick=\"zoomImage(0.25)\" title=\"Zum Masuk\" class=\"p-2 bg-slate-100 text-slate-700 hover:bg-blue-50 hover:text-blue-600 border border-slate-200 rounded-lg transition-colors flex items-center justify-center\">\n                    <i data-lucide=\"zoom-in\" class=\"w-4 h-4\"><\/i>\n                <\/button>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <script>\n        \/\/ Data configuration based on floorplan image labels\n        const locationsData = [\n            {\n                id: 'ivi',\n                label: 'IVI',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/logo-ivi.jpg',\n                description: 'Institut Informatik Visual',\n                coords: { top: 11.2, left: 6.8, width: 8.0, height: 5.6 }\n            },\n            {\n                id: 'ftsm',\n                label: 'FTSM',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/logo-ftsm-scaled.jpg',\n                description: 'Fakulti Teknologi dan Sains Maklumat',\n                coords: { top: 11.2, left: 15.4, width: 8.0, height: 5.6 }\n            },\n            {\n                id: 'fkab',\n                label: 'FKAB',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/logo-fkab.jpg',\n                description: 'Fakulti Kejuruteraan dan Alam Bina',\n                coords: { top: 11.2, left: 24.0, width: 8.0, height: 5.6 }\n            },\n            {\n                id: 'ptsl',\n                label: 'PTSL',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/logo-ptsl.jpg',\n                description: 'Perpustakaan Tun Seri Lanang',\n                coords: { top: 32.0, left: 6.8, width: 4.0, height: 11.0 }\n            },\n            {\n                id: 'bks',\n                label: 'Bahagian Keselamatan',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/LOGO-BKS-BARU-1.jpg',\n                description: 'Polis Bantuan \/ Keselamatan UKM',\n                coords: { top: 45.0, left: 6.8, width: 4.0, height: 11.0 }\n            },\n            {\n                id: 'bendahari',\n                label: 'Jabatan Bendahari',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/logo-JB.jpg',\n                description: 'Jabatan Bendahari UKM',\n                coords: { top: 58.0, left: 6.8, width: 4.0, height: 11.0 }\n            },\n            {\n                id: 'pendaftaran',\n                label: 'PENDAFTARAN',\n                file: 'pendaftaran.jpg',\n                disableHover: true,\n                description: 'Kaunter Pendaftaran Pameran',\n                coords: { top: 88.0, left: 6.8, width: 8.0, height: 4.8 }\n            },\n            {\n                id: 'akademik',\n                label: 'Akademik UKM',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/logo-akademik.jpg',\n                description: 'Pusat Pengurusan Akademik UKM',\n                coords: { top: 88.0, left: 15.4, width: 8.0, height: 4.8 }\n            },\n            {\n                id: 'penerbit',\n                label: 'Penerbit UKM',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/Penerbit.jpg',\n                description: 'Penerbit UKM \/ Diskaun Buku',\n                coords: { top: 88.0, left: 24.0, width: 8.0, height: 4.8 }\n            },\n            {\n                id: 'hep',\n                label: 'HEP-UKM',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/logo-HEP.jpg',\n                description: 'Pusat Hal Ehwal Pelajar UKM',\n                coords: { top: 88.0, left: 32.6, width: 8.0, height: 4.8 }\n            },\n            {\n                id: 'cctv',\n                label: 'CCTV',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/logo-cctv.jpg',\n                disableHover: false,\n                description: 'Sistem CCTV & Keselamatan Digital',\n                coords: { top: 31.2, left: 62.3, width: 7.5, height: 6.0 }\n            },\n            {\n                id: 'smartboard',\n                label: 'SmartBoard',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/logo-smartboard.jpg',\n                disableHover: false,\n                description: 'Paparan Interaktif SmartBoard',\n                coords: { top: 31.2, left: 70.4, width: 8.8, height: 6.0 }\n            },\n            {\n                id: 'cuepacs',\n                label: 'CUEPACS',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/Cuepacs.jpg',\n                description: 'Pertubuhan CUEPACS',\n                coords: { top: 31.2, left: 80.0, width: 8.8, height: 6.0 }\n            },\n            {\n                id: 'ewaste',\n                label: 'e-Waste',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/ewaste.jpg',\n                description: 'Pengumpulan Sisa Elektronik',\n                coords: { top: 31.2, left: 89.5, width: 8.8, height: 6.0 }\n            },\n            {\n                id: 'laptop',\n                label: 'Laptop',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/laptop.png',\n                description: 'Jualan Komputer Riba Terpakai',\n                coords: { top: 47.0, left: 94.0, width: 3.8, height: 18.5 }\n            },\n            {\n                id: 'digitalukm',\n                label: 'DigitalUKM',\n                file: 'https:\/\/www.ukm.my\/minggudigital\/wp-content\/uploads\/2026\/10\/Khidmat-Digital.jpg',\n                description: 'Pusat Teknologi Digital UKM',\n                coords: { top: 85.0, left: 63.0, width: 22.0, height: 7.5 }\n            }\n        ];\n\n        let activeItem = null;\n        let isHoveringPopover = false;\n\n        \/\/ Zoom and Pan State Variables\n        let currentZoom = 1;\n        let panX = 0;\n        let panY = 0;\n        let isDragging = false;\n        let startX = 0;\n        let startY = 0;\n\n        document.addEventListener('DOMContentLoaded', () => {\n            lucide.createIcons();\n            renderHotspots();\n            renderDirectoryList();\n            setupZoomEvents();\n\n            \/\/ Hide popover when clicking elsewhere\n            document.addEventListener('click', (e) => {\n                const popover = document.getElementById('thumbnail-popover');\n                const isClickInsideHotspot = e.target.closest('.hotspot');\n                const isClickInsideDirectory = e.target.closest('#directory-list');\n                const isClickInsidePopover = e.target.closest('#thumbnail-popover');\n\n                if (!isClickInsideHotspot && !isClickInsideDirectory && !isClickInsidePopover) {\n                    hidePopover();\n                }\n            });\n\n            \/\/ Close modal on escape key\n            document.addEventListener('keydown', (e) => {\n                if (e.key === 'Escape') closeModal();\n            });\n\n            \/\/ Close modal when clicking backdrop\n            document.getElementById('image-modal').addEventListener('click', (e) => {\n                if (e.target.id === 'image-modal') closeModal();\n            });\n        });\n\n        function renderHotspots() {\n            const container = document.getElementById('hotspots-layer');\n            container.innerHTML = '';\n\n            locationsData.forEach(item => {\n                const spot = document.createElement('div');\n                spot.className = 'hotspot';\n                spot.dataset.id = item.id;\n                spot.style.top = `${item.coords.top}%`;\n                spot.style.left = `${item.coords.left}%`;\n                spot.style.width = `${item.coords.width}%`;\n                spot.style.height = `${item.coords.height}%`;\n\n                if (item.disableHover) {\n                    spot.style.pointerEvents = 'none';\n                } else {\n                    \/\/ Event Listeners\n                    spot.addEventListener('mouseenter', (e) => showPopover(item, e));\n                    spot.addEventListener('mouseleave', () => scheduleHidePopover());\n                    spot.addEventListener('mousemove', (e) => updatePopoverPosition(e));\n                    spot.addEventListener('click', () => openModal(item));\n                }\n\n                container.appendChild(spot);\n            });\n        }\n\n        function renderDirectoryList(filter = '') {\n            const list = document.getElementById('directory-list');\n            list.innerHTML = '';\n\n            const filteredData = locationsData.filter(item => \n                item.label.toLowerCase().includes(filter.toLowerCase()) || \n                (item.description && item.description.toLowerCase().includes(filter.toLowerCase()))\n            );\n\n            const itemCountEl = document.getElementById('item-count');\n            if (itemCountEl) {\n                itemCountEl.textContent = `${filteredData.length} label`;\n            }\n\n            filteredData.forEach((item, index) => {\n                const numIndex = String(index + 1).padStart(2, '0');\n                const el = document.createElement('div');\n                el.className = `p-2.5 rounded-xl border border-slate-200 bg-white hover:border-blue-400 hover:bg-blue-50\/50 cursor-pointer transition-all flex items-center justify-between group text-xs ${activeItem?.id === item.id ? 'border-blue-500 bg-blue-50 shadow-sm' : ''}`;\n                el.dataset.id = item.id;\n\n                el.innerHTML = `\n                    <div class=\"flex items-center space-x-3 min-w-0\">\n                        <div class=\"w-7 h-7 rounded-lg bg-blue-50 text-blue-600 font-bold text-xs flex items-center justify-center border border-blue-200 group-hover:bg-blue-600 group-hover:text-white group-hover:border-blue-600 flex-shrink-0 transition-all font-mono\">\n                            ${numIndex}\n                        <\/div>\n                        <div class=\"truncate\">\n                            <h4 class=\"font-semibold text-slate-800 group-hover:text-blue-700 truncate\">${item.label}<\/h4>\n                            ${item.description ? `<p class=\"text-[10px] text-slate-400 truncate\">${item.description}<\/p>` : ''}\n                        <\/div>\n                    <\/div>\n                    <i data-lucide=\"chevron-right\" class=\"w-4 h-4 text-slate-300 group-hover:text-blue-500 group-hover:translate-x-0.5 transition-transform flex-shrink-0\"><\/i>\n                `;\n\n                el.addEventListener('mouseenter', (e) => {\n                    highlightHotspot(item.id, true);\n                    if (!item.disableHover) showPopover(item, e);\n                });\n                el.addEventListener('mouseleave', () => {\n                    highlightHotspot(item.id, false);\n                    scheduleHidePopover();\n                });\n                el.addEventListener('click', () => {\n                    if (!item.disableHover) openModal(item);\n                });\n\n                list.appendChild(el);\n            });\n\n            lucide.createIcons();\n        }\n\n        let popoverTimeout = null;\n\n        function showPopover(item, event) {\n            if (item.disableHover) return;\n            clearTimeout(popoverTimeout);\n            activeItem = item;\n\n            const popover = document.getElementById('thumbnail-popover');\n            const titleEl = document.getElementById('popover-title');\n            const imgEl = document.getElementById('popover-img');\n\n            titleEl.textContent = item.label;\n            \n            \/\/ Set image source with SVG fallback generator if file does not exist locally\n            imgEl.onerror = () => {\n                imgEl.onerror = null;\n                if (item.fallbackFiles && item.fallbackFiles.length > 0) {\n                    imgEl.src = item.fallbackFiles[0];\n                } else {\n                    imgEl.src = createSvgPlaceholder(item.label);\n                }\n            };\n            imgEl.src = item.file;\n\n            popover.classList.remove('hidden');\n            updatePopoverPosition(event);\n            highlightHotspot(item.id, true);\n        }\n\n        function updatePopoverPosition(e) {\n            const popover = document.getElementById('thumbnail-popover');\n            if (popover.classList.contains('hidden')) return;\n\n            const popWidth = 260;\n            const popHeight = 200;\n            const padding = 15;\n\n            let x = e.clientX + 15;\n            let y = e.clientY + 15;\n\n            \/\/ Keep within viewport boundaries\n            if (x + popWidth > window.innerWidth - padding) {\n                x = e.clientX - popWidth - 15;\n            }\n            if (y + popHeight > window.innerHeight - padding) {\n                y = e.clientY - popHeight - 15;\n            }\n\n            popover.style.left = `${Math.max(padding, x)}px`;\n            popover.style.top = `${Math.max(padding, y)}px`;\n        }\n\n        function scheduleHidePopover() {\n            popoverTimeout = setTimeout(() => {\n                hidePopover();\n            }, 100);\n        }\n\n        function hidePopover() {\n            const popover = document.getElementById('thumbnail-popover');\n            popover.classList.add('hidden');\n            if (activeItem) {\n                highlightHotspot(activeItem.id, false);\n                activeItem = null;\n            }\n        }\n\n        function openModalFromPopover() {\n            if (activeItem) {\n                openModal(activeItem);\n            }\n        }\n\n        function highlightHotspot(id, enable) {\n            const hotspot = document.querySelector(`.hotspot[data-id=\"${id}\"]`);\n            if (hotspot) {\n                if (enable) hotspot.classList.add('active');\n                else hotspot.classList.remove('active');\n            }\n        }\n\n        function openModal(item) {\n            hidePopover();\n            activeItem = item;\n            resetZoomImage();\n\n            const modal = document.getElementById('image-modal');\n            const card = document.getElementById('modal-card');\n            const titleEl = document.getElementById('modal-title');\n            const descEl = document.getElementById('modal-description');\n            const imgEl = document.getElementById('modal-img');\n\n            titleEl.textContent = item.label;\n            descEl.textContent = item.description || 'Gambar Penuh';\n\n            imgEl.onerror = () => {\n                imgEl.onerror = null;\n                if (item.fallbackFiles && item.fallbackFiles.length > 0) {\n                    imgEl.src = item.fallbackFiles[0];\n                } else {\n                    imgEl.src = createSvgPlaceholder(item.label, 800, 500);\n                }\n            };\n            imgEl.src = item.file;\n\n            modal.classList.remove('hidden');\n            setTimeout(() => {\n                modal.classList.remove('opacity-0');\n                card.classList.remove('scale-95');\n                card.classList.add('scale-100');\n            }, 10);\n        }\n\n        function closeModal() {\n            const modal = document.getElementById('image-modal');\n            const card = document.getElementById('modal-card');\n\n            modal.classList.add('opacity-0');\n            card.classList.remove('scale-100');\n            card.classList.add('scale-95');\n\n            setTimeout(() => {\n                modal.classList.add('hidden');\n                resetZoomImage();\n            }, 300);\n        }\n\n        function updateImageTransform() {\n            const wrapper = document.getElementById('modal-zoom-wrapper');\n            const badge = document.getElementById('zoom-badge');\n            if (wrapper) {\n                wrapper.style.transform = `translate(${panX}px, ${panY}px) scale(${currentZoom})`;\n            }\n            if (badge) {\n                badge.textContent = `${Math.round(currentZoom * 100)}%`;\n            }\n        }\n\n        function zoomImage(delta) {\n            currentZoom = Math.min(Math.max(0.75, currentZoom + delta), 4);\n            if (currentZoom === 1) {\n                panX = 0;\n                panY = 0;\n            }\n            updateImageTransform();\n        }\n\n        function resetZoomImage() {\n            currentZoom = 1;\n            panX = 0;\n            panY = 0;\n            updateImageTransform();\n        }\n\n        function setupZoomEvents() {\n            const container = document.getElementById('modal-img-container');\n            if (!container) return;\n\n            \/\/ Mouse wheel zoom\n            container.addEventListener('wheel', (e) => {\n                e.preventDefault();\n                const delta = e.deltaY < 0 ? 0.2 : -0.2;\n                zoomImage(delta);\n            }, { passive: false });\n\n            \/\/ Drag \/ Pan interactions\n            container.addEventListener('mousedown', (e) => {\n                if (currentZoom > 1) {\n                    isDragging = true;\n                    startX = e.clientX - panX;\n                    startY = e.clientY - panY;\n                    container.classList.add('cursor-grabbing');\n                }\n            });\n\n            window.addEventListener('mousemove', (e) => {\n                if (isDragging) {\n                    panX = e.clientX - startX;\n                    panY = e.clientY - startY;\n                    updateImageTransform();\n                }\n            });\n\n            window.addEventListener('mouseup', () => {\n                isDragging = false;\n                const container = document.getElementById('modal-img-container');\n                if (container) container.classList.remove('cursor-grabbing');\n            });\n\n            \/\/ Mobile Touch Pan\n            container.addEventListener('touchstart', (e) => {\n                if (e.touches.length === 1 && currentZoom > 1) {\n                    isDragging = true;\n                    startX = e.touches[0].clientX - panX;\n                    startY = e.touches[0].clientY - panY;\n                }\n            });\n\n            container.addEventListener('touchmove', (e) => {\n                if (isDragging && e.touches.length === 1) {\n                    panX = e.touches[0].clientX - startX;\n                    panY = e.touches[0].clientY - startY;\n                    updateImageTransform();\n                }\n            });\n\n            container.addEventListener('touchend', () => {\n                isDragging = false;\n            });\n        }\n\n        \/\/ Search handler\n        function handleSearch(val) {\n            renderDirectoryList(val);\n        }\n\n        function createSvgPlaceholder(title, width = 300, height = 200) {\n            const svgString = `\n                <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\">\n                    <rect width=\"100%\" height=\"100%\" fill=\"#f8fafc\" stroke=\"#cbd5e1\" stroke-width=\"2\"\/>\n                    <rect x=\"10\" y=\"10\" width=\"${width - 20}\" height=\"${height - 20}\" rx=\"12\" fill=\"#ffffff\" stroke=\"#e2e8f0\" stroke-width=\"1.5\"\/>\n                    <g transform=\"translate(${width\/2}, ${height\/2 - 15})\" text-anchor=\"middle\">\n                        <circle cx=\"0\" cy=\"-10\" r=\"28\" fill=\"#eff6ff\"\/>\n                        <path d=\"M-10 5 L10 5 L0 -15 Z\" fill=\"#3b82f6\"\/>\n                        <text x=\"0\" y=\"32\" font-family=\"Inter, sans-serif\" font-weight=\"bold\" font-size=\"18\" fill=\"#1e293b\">${title}<\/text>\n                        <text x=\"0\" y=\"55\" font-family=\"Inter, sans-serif\" font-size=\"12\" fill=\"#94a3b8\">(Imej Pratonton)<\/text>\n                    <\/g>\n                <\/svg>\n            `;\n            return `data:image\/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`;\n        }\n\n        function handleFloorplanError(img) {\n            img.onerror = null;\n            img.src = createSvgPlaceholder('Pelan Lantai Utama', 1000, 600);\n        }\n    <\/script>\n<\/body>\n<\/html>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Pameran Pelan Lantai Interaktif Pameran Pelan Lantai Interaktif Pameran Halakan kursor pada label untuk pratonton thumbnail &#038; klik untuk imej penuh. Senarai Label &#038; Lokasi<a class=\"ut-readmore\" href=\"https:\/\/www.ukm.my\/minggudigital\/pameran\/\"> &#8230;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":5,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"footnotes":""},"class_list":["post-3873","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.ukm.my\/minggudigital\/wp-json\/wp\/v2\/pages\/3873","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ukm.my\/minggudigital\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.ukm.my\/minggudigital\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.ukm.my\/minggudigital\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ukm.my\/minggudigital\/wp-json\/wp\/v2\/comments?post=3873"}],"version-history":[{"count":62,"href":"https:\/\/www.ukm.my\/minggudigital\/wp-json\/wp\/v2\/pages\/3873\/revisions"}],"predecessor-version":[{"id":4110,"href":"https:\/\/www.ukm.my\/minggudigital\/wp-json\/wp\/v2\/pages\/3873\/revisions\/4110"}],"wp:attachment":[{"href":"https:\/\/www.ukm.my\/minggudigital\/wp-json\/wp\/v2\/media?parent=3873"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}