{"id":17,"date":"2026-04-07T16:50:12","date_gmt":"2026-04-07T14:50:12","guid":{"rendered":"https:\/\/servidorencasa.com\/?page_id=17"},"modified":"2026-04-08T16:10:41","modified_gmt":"2026-04-08T14:10:41","slug":"panel-timbre","status":"publish","type":"page","link":"https:\/\/servidorencasa.com\/index.php\/panel-timbre\/","title":{"rendered":"Panel timbre"},"content":{"rendered":"    <style>\n      :root{\n        --bg:#0b0b0b;\n        --bg2:#151515;\n        --fg:#eee;\n        --b2:#2b2b2b;\n        --btn:#1f6feb;\n        --ok:#1a7f37;\n        --err:#b3261e;\n        --warn:#e6b800;\n      }\n\n      .sec-panel-wrap[data-theme=\"light\"]{\n        --bg:#f6f8fa;\n        --bg2:#ffffff;\n        --fg:#111;\n        --b2:#d0d7de;\n        --btn:#0969da;\n      }\n\n      .sec-panel-wrap *{box-sizing:border-box}\n\n      .sec-panel-wrap{\n        width:min(1100px,95vw);\n        margin:30px auto;\n        background:var(--bg);\n        color:var(--fg);\n        font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;\n      }\n\n      .sec-panel-card{\n        background:var(--bg2);\n        border:1px solid var(--b2);\n        border-radius:18px;\n        box-shadow:0 10px 30px rgba(0,0,0,.25);\n        padding:1.25rem 1.5rem 1.5rem;\n        position:relative;\n      }\n\n      .sec-panel-header{\n        display:flex;\n        justify-content:space-between;\n        gap:12px;\n        align-items:center;\n        flex-wrap:wrap;\n        margin-bottom:18px;\n      }\n\n      .sec-panel-header h1{\n        margin:.25rem 0;\n        font-size:1.6rem;\n      }\n\n      .sec-panel-theme{\n        background:transparent;\n        color:inherit;\n        border:1px solid var(--b2);\n        border-radius:10px;\n        padding:.45rem .6rem;\n        cursor:pointer;\n      }\n\n      .sec-panel-grid{\n        display:grid;\n        grid-template-columns:1.1fr .9fr;\n        gap:18px;\n      }\n\n      .sec-box{\n        background:transparent;\n        border:1px solid var(--b2);\n        border-radius:16px;\n        padding:18px;\n      }\n\n      .sec-box h3{\n        margin:0 0 12px;\n        font-size:1.25rem;\n      }\n\n      .sec-big{\n        font-size:1.5rem;\n        font-weight:800;\n        margin:.5rem 0;\n      }\n\n      .sec-muted{\n        opacity:.85;\n      }\n\n      .sec-alerta{\n        margin-top:.8rem;\n        padding:.7rem .9rem;\n        border:1px solid var(--warn);\n        border-radius:10px;\n        background:#ffec8a;\n        color:#111;\n        font-weight:800;\n      }\n\n      .sec-sound-row{\n        margin-top:14px;\n        display:flex;\n        align-items:center;\n        gap:12px;\n        flex-wrap:wrap;\n      }\n\n      .sec-sound-row input[type=\"range\"]{\n        width:180px;\n      }\n\n      .sec-panel-wrap button.primary{\n        padding:.8rem 1rem;\n        border-radius:10px;\n        border:1px solid var(--btn);\n        background:var(--btn);\n        color:#fff;\n        font-weight:700;\n        cursor:pointer;\n      }\n\n      .sec-tabla-scroll{\n        max-height:520px;\n        overflow-y:auto;\n        border:1px solid var(--b2);\n        border-radius:12px;\n      }\n\n      .sec-panel-wrap table{\n        width:100%;\n        border-collapse:collapse;\n      }\n\n      .sec-panel-wrap thead th{\n        position:sticky;\n        top:0;\n        background:var(--bg2);\n        z-index:2;\n      }\n\n      .sec-panel-wrap th,\n      .sec-panel-wrap td{\n        text-align:left;\n        padding:10px;\n        border-bottom:1px solid var(--b2);\n        font-size:.95rem;\n      }\n\n      .sec-panel-wrap th{\n        opacity:.85;\n      }\n\n      .sec-col-num{\n        width:70px;\n        text-align:center;\n      }\n\n      @media (max-width: 900px){\n        .sec-panel-grid{\n          grid-template-columns:1fr;\n        }\n      }\n    <\/style>\n\n    <div class=\"sec-panel-wrap\" id=\"sec-panel-wrap\" data-theme=\"dark\">\n      <div class=\"sec-panel-card\">\n        <div class=\"sec-panel-header\">\n          <div>\n            <h1>\ud83d\udd14 Panel del timbre<\/h1>\n            <div class=\"sec-muted\">\n              Timbre: <strong>Timbre de Tino<\/strong>\n              \u00b7 Clave: <strong>Tinolois123<\/strong>\n              \u00b7 Slug: <strong>tinolois<\/strong>\n            <\/div>\n          <\/div>\n\n          <button id=\"secPanelThemeToggle\" class=\"sec-panel-theme\" type=\"button\">\ud83c\udf19<\/button>\n        <\/div>\n\n        <div class=\"sec-panel-grid\">\n          <section class=\"sec-box\">\n            <h3>\u00bfQui\u00e9n llama...?<\/h3>\n\n            <div id=\"secUltimoTexto\" class=\"sec-big\">\n                              Todav\u00eda no ha llamado nadie.\n                          <\/div>\n\n            <div class=\"sec-muted\">\n              <strong>Fecha:<\/strong> <span id=\"secUltimaFecha\">--\/--\/----<\/span><br>\n              <strong>Hora:<\/strong> <span id=\"secUltimaHora\">--:--<\/span>\n            <\/div>\n\n            <div id=\"secAlertaSuplantacion\" class=\"sec-alerta\" style=\"display:none;\">\n              \u26a0\ufe0f TEN CUIDADO: POSIBLE SUPLANTACI\u00d3N.\n            <\/div>\n\n            <div class=\"sec-muted\" style=\"margin-top:1rem\">\n              Si no oyes el sonido, pulsa el bot\u00f3n para activarlo en este dispositivo.\n            <\/div>\n\n            <div class=\"sec-sound-row\">\n              <button class=\"primary\" type=\"button\" id=\"secActivarSonido\">Activar sonido<\/button>\n              <span>Volumen<\/span>\n              <input id=\"secVolumen\" type=\"range\" min=\"0\" max=\"1\" step=\"0.01\" value=\"1\">\n              <span id=\"secVolumenTxt\">100%<\/span>\n            <\/div>\n          <\/section>\n\n          <section class=\"sec-box\">\n            <h3>Resumen<\/h3>\n            <div class=\"sec-muted\">\n              Este panel se actualiza autom\u00e1ticamente cada 5 segundos.<br><br>\n              Muestra:\n              <br>\u00b7 \u00daltimo visitante\n              <br>\u00b7 Fecha y hora\n              <br>\u00b7 Aviso de posible suplantaci\u00f3n\n              <br>\u00b7 Historial reciente de llamadas\n            <\/div>\n          <\/section>\n        <\/div>\n\n        <section class=\"sec-box\" style=\"margin-top:18px;\">\n          <h3>\u00bfQui\u00e9n ha llamado a mi puerta?<\/h3>\n\n          <div class=\"sec-tabla-scroll\">\n            <table>\n              <thead>\n                <tr>\n                  <th class=\"sec-col-num\">N\u00ba<\/th>\n                  <th>Fecha<\/th>\n                  <th>Hora<\/th>\n                  <th>Nombre<\/th>\n                  <th>Relaci\u00f3n<\/th>\n                  <th>Alerta<\/th>\n                <\/tr>\n              <\/thead>\n              <tbody id=\"secHistorialBody\">\n                              <tr><td colspan=\"6\" class=\"sec-muted\">No hay llamadas todav\u00eda.<\/td><\/tr>\n                            <\/tbody>\n            <\/table>\n          <\/div>\n        <\/section>\n      <\/div>\n\n      <audio id=\"secPanelRing\" preload=\"auto\">\n        <source src=\"\/wp-content\/uploads\/sonidos\/timbre.mp3\" type=\"audio\/mpeg\">\n      <\/audio>\n    <\/div>\n\n    <script>\n    (() => {\n      const ajaxUrl = \"https:\\\/\\\/servidorencasa.com\\\/wp-admin\\\/admin-ajax.php\";\n      const slug = \"tinolois\";\n\n      const root = document.getElementById('sec-panel-wrap');\n      const themeBtn = document.getElementById('secPanelThemeToggle');\n      const ring = document.getElementById('secPanelRing');\n      const btnActivar = document.getElementById('secActivarSonido');\n      const volumen = document.getElementById('secVolumen');\n      const volumenTxt = document.getElementById('secVolumenTxt');\n      const ultimoTexto = document.getElementById('secUltimoTexto');\n      const ultimaFecha = document.getElementById('secUltimaFecha');\n      const ultimaHora = document.getElementById('secUltimaHora');\n      const alerta = document.getElementById('secAlertaSuplantacion');\n      const historialBody = document.getElementById('secHistorialBody');\n\n      const THEME_KEY = 'panel_theme_wp';\n      const VOL_KEY = 'panel_ring_volume_wp';\n      const LAST_KEY = 'panel_last_fecha_wp_' + slug;\n\n      function applyTheme(mode){\n        root.setAttribute('data-theme', mode);\n        localStorage.setItem(THEME_KEY, mode);\n        themeBtn.textContent = (mode === 'light') ? '\u2600\ufe0f' : '\ud83c\udf19';\n      }\n\n      applyTheme(localStorage.getItem(THEME_KEY) || 'dark');\n\n      themeBtn.addEventListener('click', () => {\n        applyTheme(root.getAttribute('data-theme') === 'light' ? 'dark' : 'light');\n      });\n\n      function getSavedVol(){\n        const v = parseFloat(localStorage.getItem(VOL_KEY) || '1');\n        return Number.isFinite(v) ? Math.max(0, Math.min(1, v)) : 1;\n      }\n\n      function applyVolume(v){\n        if (!ring) return;\n        ring.volume = v;\n        volumen.value = String(v);\n        volumenTxt.textContent = Math.round(v * 100) + '%';\n        localStorage.setItem(VOL_KEY, String(v));\n      }\n\n      applyVolume(getSavedVol());\n\n      volumen.addEventListener('input', () => {\n        applyVolume(parseFloat(volumen.value || '1'));\n      });\n\n      btnActivar.addEventListener('click', async () => {\n        try{\n          ring.currentTime = 0;\n          await ring.play();\n          ring.pause();\n          ring.currentTime = 0;\n          btnActivar.textContent = 'Sonido listo';\n        }catch(e){\n          btnActivar.textContent = 'Intenta otra vez';\n        }\n      });\n\n      function pad(n){ return n < 10 ? '0' + n : '' + n; }\n\n      function formateaFechaHora(fechaRaw){\n        if (!fechaRaw) {\n          return { fecha: '--\/--\/----', hora: '--:--' };\n        }\n\n        const d = new Date(String(fechaRaw).replace(' ', 'T'));\n        if (isNaN(d.getTime())) {\n          return { fecha: '--\/--\/----', hora: '--:--' };\n        }\n\n        return {\n          fecha: pad(d.getDate()) + '\/' + pad(d.getMonth() + 1) + '\/' + d.getFullYear(),\n          hora: pad(d.getHours()) + ':' + pad(d.getMinutes())\n        };\n      }\n\n      async function refrescarUltimo(){\n        try{\n          const url = new URL(ajaxUrl, window.location.origin);\n          url.searchParams.set('action', 'sec_ultimo_visitante');\n          url.searchParams.set('slug', slug);\n          url.searchParams.set('ts', Date.now());\n\n          const r = await fetch(url.toString(), { cache: 'no-store' });\n          const j = await r.json();\n\n          if (!j || !j.ok) return;\n\n          const fh = formateaFechaHora(j.fecha || '');\n          const nombre = (j.nombre || '').toUpperCase();\n          const relacion = (j.relacion || '').toUpperCase();\n\n          if (nombre) {\n            ultimoTexto.textContent = 'Te ha llamado a la puerta tu ' + relacion + ' ' + nombre + ' (' + fh.hora + ')';\n          } else {\n            ultimoTexto.textContent = 'Todav\u00eda no ha llamado nadie.';\n          }\n\n          ultimaFecha.textContent = fh.fecha;\n          ultimaHora.textContent = fh.hora;\n          alerta.style.display = j.sospechoso ? 'block' : 'none';\n\n          const prev = localStorage.getItem(LAST_KEY) || '';\n          const actual = j.fecha || '';\n\n          if (actual && actual !== prev) {\n            localStorage.setItem(LAST_KEY, actual);\n\n            const d = new Date(String(actual).replace(' ', 'T'));\n            const ageMs = Date.now() - d.getTime();\n\n            if (!isNaN(d.getTime()) && ageMs >= 0 && ageMs < 90000) {\n              try{\n                ring.currentTime = 0;\n                await ring.play();\n              }catch(e){}\n            }\n\n            await refrescarHistorial();\n          }\n\n        } catch(e){}\n      }\n\n      async function refrescarHistorial(){\n        try{\n          const url = new URL(ajaxUrl, window.location.origin);\n          url.searchParams.set('action', 'sec_historial_llamadas');\n          url.searchParams.set('slug', slug);\n          url.searchParams.set('ts', Date.now());\n\n          const r = await fetch(url.toString(), { cache: 'no-store' });\n          const j = await r.json();\n\n          if (!j || !j.ok || !Array.isArray(j.items)) return;\n\n          if (j.items.length === 0) {\n            historialBody.innerHTML = '<tr><td colspan=\"6\" class=\"sec-muted\">No hay llamadas todav\u00eda.<\/td><\/tr>';\n            return;\n          }\n\n          historialBody.innerHTML = j.items.map((fila, index) => {\n            return '<tr>' +\n              '<td class=\"sec-col-num\">' + (index + 1) + '<\/td>' +\n              '<td>' + (fila.fecha || '') + '<\/td>' +\n              '<td>' + (fila.hora || '') + '<\/td>' +\n              '<td>' + (fila.nombre || '') + '<\/td>' +\n              '<td>' + (fila.relacion || '') + '<\/td>' +\n              '<td>' + (fila.sospechoso ? '\u26a0\ufe0f S\u00ed' : 'No') + '<\/td>' +\n            '<\/tr>';\n          }).join('');\n        } catch(e){}\n      }\n\n      refrescarUltimo();\n      refrescarHistorial();\n      setInterval(refrescarUltimo, 5000);\n    })();\n    <\/script>\n    \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-17","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/servidorencasa.com\/index.php\/wp-json\/wp\/v2\/pages\/17","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/servidorencasa.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/servidorencasa.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/servidorencasa.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/servidorencasa.com\/index.php\/wp-json\/wp\/v2\/comments?post=17"}],"version-history":[{"count":1,"href":"https:\/\/servidorencasa.com\/index.php\/wp-json\/wp\/v2\/pages\/17\/revisions"}],"predecessor-version":[{"id":18,"href":"https:\/\/servidorencasa.com\/index.php\/wp-json\/wp\/v2\/pages\/17\/revisions\/18"}],"wp:attachment":[{"href":"https:\/\/servidorencasa.com\/index.php\/wp-json\/wp\/v2\/media?parent=17"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}