manniru
4/24/2018 - 3:32 AM

A basic hyperHTML + Firebase example. 100% client side.

A basic hyperHTML + Firebase example. 100% client side.

<!doctype html>
<html lang="en">
  <head>
    <title>hyperHTML &amp; Firebase</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <style>
    html { font-family: sans-serif; }
    html, body, ul, p { padding: 0; margin: 0; }
    ul, li { list-style: none; }
    body > p, li { padding: 8px; }
    li:nth-child(2n + 1) { background-color: #eee; }
    li > * { display: block; }
    li > span:last-child { font-size: .9em; text-align: right; color: #666; }
    li > a, li > span:first-child { font-size: 1.1em; font-weight: bold;
                                    text-decoration: none; line-height: 32px; }
    </style>
    <!-- JS dependencies: hyperHTML and Firebase -->
    <script src="https://unpkg.com/hyperhtml@latest/min.js"></script>
    <script src="https://www.gstatic.com/firebasejs/4.2.0/firebase.js"></script>
  </head>
  <body></body>
  <script>
    (() => {
      const {bind, wire} = hyperHTML;

      // in this example, we are not going
      // to relate any specific object to wires,
      // so we can just use html`content`
      const html = (...args) => wire()(...args);

      // the Firebase DB
      const db = firebase
        .initializeApp({databaseURL: 'https://hacker-news.firebaseio.com'})
        .database()
        .ref( 'v0' );

      // let's use the body as hyperHTML context to populate
      bind(document.body)
      `${{
        // show an indication that something is happening
        placeholder: {html: '<p>Loading ...</p>'},

        // while downloading latest top stories
        // and creating the list of all items
        any: new Promise(resolve => {
          db.child('topstories')
            .on('value', snap => {
              resolve(
                // instead of "Loading ..."
                // we want now to put a UL element
                // and show all the received items
                html`<ul>${mapItems(snap.val())}</ul>`
              );
            });
        })
      }}`;

      function mapItems(items) {
        // per each id we create an LI element
        return items.map(
          id => html`<li data-id=${id}>${loadItem(id)}</li>`
        );
      }

      function loadItem(id) {
        // per each LI we load asynchronously basic story info
        return {
          placeholder: `fetching ${id} ...`,
          any: new Promise(resolve => {
            db.child(`/item/${id}`)
              .once('value', snap => {
                const item = snap.val();
                const hostname = item.hostname || item.url;
                resolve(html`
                ${{any: hostname ?
                  // if there is an hostname/url to show
                  // put a link and a shortened hostname info
                  html`<a href=${item.url} target=_blank>${item.title}</a>
                       <small>
                       ${new URL(hostname).hostname.replace(/^www\./, '')}
                       </small>`:

                  // otherwise just show the title
                  html`<span>${item.title}</span>`
                }}
                <!-- show some extra info -->
                <span>${item.score} points by <b>${item.by}</b></span>`);
              });
          })
        };
      }

    })();
  </script>
</html>