Nat TaylorBlog, AI, Product Management & Tinkering

Page Previews

Published on .

As of today, if you hover over an internal blog post link on my site on a wide screen, a page preview will appear in the right margin as demonstrated below, in order to help you decide whether or not to click.

Page Preview Demo

Caching and simplicity already make page loads on my site pretty fast (50-200ms,) but I always liked the way that Wikipedia designed page previews. Still, I thought the implementation was too complicated to warrant. Then today I saw an alternative implementation on jefftk.com that used iframes, which is both simple and fairly fast.

The implementation does a few interesting things:

Love it? Hate it? Let me know with an email to nattaylor@gmail.com

Here is the code.

<script type="text/javascript">

window.onload = previewSetup(250, 3000, 1000, 'https://nattaylor.com/blog');

function previewSetup(delay, timeout, minwidth, pattern) {
/**
 * Show a iframe preview of a link on hover (a la Wikipedia)
 * 
 * Usage: window.onload = previewSetup(500, 3000, 1000);
 * @param  Number delay    time to wait to show preview
 * @param  Number timeout  time in ms for preview to linger
 * @param  Number minwidth minimum screen width to display the preview
 * @return {[type]}          [description]
 */
  // For blog links, show a preview
  document.querySelectorAll("a[href*='"+pattern+"']").forEach(function(e) {
      e.addEventListener('mouseover', function(e) {
        window.clearTimeout(window.previewDelay);
        window.previewDelay = setTimeout(preview, delay, e);
      });
    }
  )

  // Create & append the elements, plus configure event listeners
  function preview(e) {
    if (window.outerWidth < minwidth) {
      return
    }
    window.clearTimeout(window.previewTimeout);
    href = e.target.href;

    iwrap = document.createElement("iwrap")
    iwrap.id = "preview-wrapper";
    iwrap.addEventListener("click", function() {document.location = href});

    iframe = document.createElement("iframe");
    iframe.id = "preview";
    iframe.setAttribute("sandbox", "allow-same-origin");
    iframe.src=href;
    iframe.scrolling="no";
    
    // Hide the header within the preview
    iframe.addEventListener( "load", function(e) {
      document
        .querySelector("#preview")
        .contentDocument
        .querySelector("body > header")
        .style.display="none";
    })

    iwrap.addEventListener( "mouseover", function (e) {
      window.clearTimeout(previewTimeout);
      e.target.addEventListener("mouseout", function(e) {
        window.previewTimeout = window.setTimeout(function() {
          if (document.querySelector("#preview-wrapper")) {
            document.querySelector("#preview-wrapper").remove();
          }
        }, timeout);
      })
    });

    e.target.addEventListener( "mouseout", function(e) {
      window.clearTimeout(window.previewTimeout);
      window.previewTimeout = window.setTimeout(function() {
        if (document.querySelector("#preview-wrapper")) {
          document.querySelector("#preview-wrapper").remove();
        }
      }, timeout);
    })
    if (document.querySelector("#preview-wrapper")) {
      document.querySelector("#preview-wrapper").remove();
    }
    iwrap.appendChild(iframe);
    document.body.appendChild(iwrap);
    return true;
  }
}
</script>
<style type="text/css">
  iframe#preview {
    position: absolute;
    right: -400px;
    bottom: 0;
    height: 400px;
    width:400px;
    border:1px solid gray;
    background-color:white;
    filter: drop-shadow(0 0 0.75rem gray);
    animation: slide 0.5s forwards;
    pointer-events: none;
  }

  #preview-wrapper {
    position: absolute;
    height: 400px;
    width:400px;
    bottom: 0;
    right:0;
  }

@keyframes slide {
    to { right: 0; }
}
</style>

Post Navigation

«
»