Ctrl K
ComunidadGuías…

chattermate-test/ui-test.html

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ChatterMate UI test</title>
<style>
  * { box-sizing: border-box; }
  body { font-family: system-ui; margin: 0; padding: 24px; background: #f7f7f5; color: #1c1c1e; }
  h1 { margin: 0 0 2px; font-size: 20px; }
  .hint { color: #666; font-size: 13px; margin-bottom: 16px; }
  .banner { display: none; background: #fdecea; border: 1px solid #f5c2bd; color: #8b2415; padding: 12px 14px; border-radius: 10px; margin-bottom: 14px; font-size: 13px; line-height: 1.6; }
  .banner code { background: rgba(0,0,0,.06); padding: 1px 5px; border-radius: 4px; }
  .controls button { margin: 3px; padding: 8px 14px; border: 1px solid #ccc; border-radius: 8px; background: #fff; cursor: pointer; }
  .controls button:hover { border-color: #f34611; }
  #log { margin-top: 14px; font: 12px/1.6 monospace; background: #fff; border: 1px solid #ddd; border-radius: 8px; padding: 10px; height: 170px; overflow: auto; white-space: pre-wrap; }
  .overlay { position: fixed; top: 30%; right: 40px; width: 220px; padding: 18px; background: rgba(110, 70, 220, 0.92); color: #fff; border-radius: 12px; z-index: 100; font-size: 13px; }
  .tall { height: 1400px; background: linear-gradient(#eee, #ddd); margin-top: 24px; border-radius: 12px; padding: 16px; color: #999; }
  a { color: #f34611; }
</style>
</head>
<body>
<h1 id="title">ChatterMate UI test</h1>
<p class="hint"><a href="ui-options.html">← all scenarios</a> · <span id="mode-label"></span></p>

<div class="banner" id="banner"></div>

<div class="controls">
  <button onclick="api('open')">open()</button>
  <button onclick="api('close')">close()</button>
  <button onclick="api('toggle')">toggle()</button>
  <button onclick="api('isOpen')">isOpen()</button>
  <button onclick="api('open', { message: 'Tell me about pricing' })">open({message})</button>
  <button onclick="api('hideLauncher')">hideLauncher()</button>
  <button onclick="api('showLauncher')">showLauncher()</button>
  <button onclick="api('setPosition', { side: 'left', bottom: 60, offset: 40 })">setPosition(left, 60, 40)</button>
  <button onclick="api('setPosition', { bottom: 20, right: 20 })">setPosition(legacy {bottom,right})</button>
  <button data-chattermate-open>data-chattermate-open</button>
  <button id="my-trigger">#my-trigger (trigger option)</button>
</div>
<div id="log"></div>
<div class="overlay" id="z-overlay" hidden>Fixed overlay at z-index 100 — with the z-index card, the widget stays UNDER this box.</div>
<div class="tall">Scroll filler — check the widget stays fixed while scrolling.</div>

<script>
  const params = new URLSearchParams(location.search)
  const settings = JSON.parse(localStorage.getItem('cm-test-settings') || '{}')
  const mode = settings.mode || 'stub'
  document.getElementById('title').textContent = params.get('title') || 'ChatterMate UI test'
  document.getElementById('mode-label').textContent = 'mode: ' + mode

  function log(msg) {
    const el = document.getElementById('log')
    el.textContent += msg + '\n'
    el.scrollTop = el.scrollHeight
    console.log('[harness]', msg)
  }

  function showBanner(html) {
    const el = document.getElementById('banner')
    el.innerHTML = html
    el.style.display = 'block'
  }

  // Every control goes through here, so a loader that failed to load reports itself
  // instead of the buttons silently doing nothing.
  function api(method, arg) {
    if (!window.ChatterMate) {
      log('⚠ ChatterMate is not loaded — see the message above')
      return
    }
    const result = window.ChatterMate[method](arg)
    if (method === 'isOpen') log('isOpen: ' + result)
  }

  if (params.get('config') && JSON.parse(params.get('config')).zIndex) {
    document.getElementById('z-overlay').hidden = false
  }

  if (mode === 'stub') {
    // A fake widget frame (stub-frame.html, served by server.js at the path the
    // loader frames) instead of the real backend. It does the real handshake, so its
    // messages pass the loader's checks — including the dashboard widget_display
    // defaults used by scenarios 10 and 11, read from this page's URL.
    window.chattermateId = 'stub-widget-id'
    window.chattermateBaseUrl = window.location.origin + '/stub/api/v1'
    log('stub mode → fake frame from ' + window.chattermateBaseUrl)
  } else {
    window.chattermateId = settings.widgetId || ''
    // Without this the loader falls back to the URL baked in at build time, which for
    // a production build is the cloud API — not your local backend.
    window.chattermateBaseUrl = settings.baseUrl || 'http://localhost:8000/api/v1'
    log('real mode → ' + window.chattermateBaseUrl)
    if (!window.chattermateId) {
      showBanner('No <strong>Widget ID</strong> set for real mode. Add one on the <a href="ui-options.html">gallery page</a>, or switch back to Stub mode.')
    }
  }

  // Scenario config. The harness always wires #my-trigger (unless the scenario sets
  // its own selector) so that button works on every card, not only the trigger one.
  const scenarioConfig = params.get('config') ? JSON.parse(params.get('config')) : {}
  if (!scenarioConfig.trigger) scenarioConfig.trigger = '#my-trigger'
  window.chattermateConfig = scenarioConfig
  if (params.get('config')) log('chattermateConfig: ' + params.get('config'))

  // The loader comes from the FRONTEND origin (vite in dev, the dashboard origin in
  // production) — the same place the generated embed snippet points at. It is never
  // copied into this folder, where it would go stale and test an old widget.
  // ('/chattermate.min.js' is a stale saved setting from an earlier version.)
  const savedLoader = settings.loaderUrl === '/chattermate.min.js' ? '' : settings.loaderUrl
  // Scheme follows the page — a hardcoded http:// would be blocked as mixed content
  // if this harness is ever served over https.
  const loaderUrl = savedLoader || `${location.protocol}//localhost:5173/webclient/chattermate.min.js`
  const s = document.createElement('script')
  s.src = loaderUrl
  s.onload = function () {
    if (!window.ChatterMate) {
      showBanner('Loaded <code>' + loaderUrl + '</code> but it never defined <code>window.ChatterMate</code> — is that file really the widget loader?')
      return
    }
    log('loader ready: ' + loaderUrl)
    ;['ready', 'open', 'close'].forEach(function (ev) {
      ChatterMate.on(ev, function () { log('event: ' + ev) })
    })
    ChatterMate.on('unread', function (count) { log('event: unread ' + count) })
  }
  s.onerror = function () {
    showBanner(
      'Could not load the widget loader from <code>' + loaderUrl + '</code>, so every button on this page does nothing.<br>' +
      'Start the frontend with <code>cd ../frontend &amp;&amp; npm run dev</code> (it serves the loader), ' +
      'and build the loader once with <code>npm run build:webclient:prod</code>. ' +
      'Or set a different Loader URL on the <a href="ui-options.html">gallery page</a>.'
    )
  }
  document.head.appendChild(s)
</script>
</body>
</html>