Turning Text into a Tweetstorm

With tongue firmly in cheek, I created this script to take a chunk of text and break it up into a tweetstorm, for "readability". Sort of like the opposite of something like Mercury Reader. If the irony is lost on you, it's a gentle ribbing of people who chose Twitter to publish long-form content, instead of, you know, readable paragraphs.

See the Pen Turning Text into a Tweetstorm by Chris Coyier (@chriscoyier) on CodePen.

It might be fun to look at how it works.

First, we need to bust up the text into an array of sentences.

We aren't going to do any fancy analysis of where the text is on the page, although is presumably some algorithmic way to do that. Let's just say we have:

<main id="text">
   Many sentences in here. So many sentences. Probably dozens of them.
</main>

Let's get our hands on that text, minus any HTML, like this:

let content = document.querySelector("#text").textContent;

Now we need to break that up into sentences. That could be as simple as splitting on periods, like content.split(". "), but that doesn't use any intelligence at all. For example, a sentence like "Where are you going, Mr. Anderson?" would be broken at the end of "Mr." and not at the "?", which ain't great.

This is find something on Stack Overflow territory!

This answer is pretty good. We'll do:

let contentArray = content.replace(‚Äč/([.?!])\s*(?=[A-Z])/g, "$1|").split("|"); 

I didn't bother to try and really dig into how it works, but at a glance, it looks like it deals with a few common sentence-ending punctuation types, and also those "Mr. Anderson" situations somehow.

We need some tweet templates.

There are two: the top one that kicks off the thread and reply tweets. We should literally make a template, because we'll need to loop over that reply tweet as many times as needed and that seems like way to go.

I reached for Handlebars, honestly because it's the first one I thought of. I probably could have gone for the ever-simpler Mustache, but whatever it's just a demo. I also couldda/shouldda gone with a template via Template Literals.

To make the template, the first thing I did was create a tweet with mock data in just HTML and CSS, like I was just devving out a component from scratch.

<div class="tweet">
  <div class="user">
    <img src="https://cdn.css-tricks.com/fake-user.svg" alt="" class="user-avatar">
    <div class="user-fullname">Jimmy Fiddlecakes</div>
    <div class="user-username">@everythingmatters</div>
  </div>
  <div class="tweet-text">
    Blah blah blah important words. 1/80
  </div>
  <time class="tweet-time">
    5:48 PM - 15 Sep 2017
  </time>

  yadda yadda yadda

I wrote my own HTML and CSS, but used DevTools to poke at the real Twitter design and stole hex codes and font sizes and stuff as much as I could so it looked real.

To make those tweet chunks of HTML into actual templates, I wrapped them up in script tags how Handlebars does it:

Now I can:

// Turn the template into a function I can call to compile it:
let mainTweetSource = document.querySelector("#main-tweet-template").innerText;
let mainTweetTemplate = Handlebars.compile(mainTweetSource);

// Compile it whenever:
let mainTweetHtml = mainTweetTemplate(data);

The data there is the useful bit. Kind of the whole point of templates.

What is "data" in a template like this? Here's stuff:

Which we can represent in an object, just like Handlebars wants:

let mainTweetData = {
  "avatar": "200/abott@adorable.io.png",
  "user-fullname": "Jimmy Fiddlecakes",
  "user-username": "@everythingmatters",
  "tweet-text": "", // from our array!
  "tweet-time": "5:48 PM - 15 Sep 2017",
  "comments": contentArray.length + 1,
  "retweets": Math.floor(Math.random() * 100),
  "loves": Math.floor(Math.random() * 200),
  "tweet-number": 1,
  "tweet-total": contentArray.length
};

Now we loop over our sentences and stitch together the templates.

// .shift() off the first sentence and compile the main tweet template first
let mainTweetHtml = mainTweetTemplate(mainTweetData);

let allSubtweetsHTML = "";

// Loop over the rest of the sentences
contentArray.forEach(function(sentence, i) {

   let subtweet_data = {
     // gather up the data fresh each time, randomzing numbers and
     // most importantly plopping in the new sentence:
     "tweet-text": sentence,
     ...
   };

   let subTweetHtml = subTweetTemplate(subtweetData);
   allSubtweetsHTML += subTweetHtml;

}

// Now dump out all this HTML somewhere onto the page:
document.querySelector("#content").innerHTML = `
  <div class="all-tweets-container">
    ${mainTweetHtml}
    ${allSubtweets}
  </div>
`;

That should do it!

I'm sure there are lots of ways to improve this, so feel free to fork the Pen and have at it. Ultimate points would be to make it a browser extension.