<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Tim G. Thomas</title>
    <link>http://timgthomas.com/</link>
    
    <atom:link href="http://timgthomas.com/feed.xml" rel="self" type="application/rss+xml"/>
    
    <description></description>
    <pubDate>Fri, 17 Jan 2025 06:38:35 GMT</pubDate>
    <generator>http://hexo.io/</generator>
    
    <item>
      <title>Homepod Hijinks: Reading Temperatures with Shortcuts and the Command Line</title>
      <link>http://timgthomas.com/2025/01/homepod-hijinks/</link>
      <guid>http://timgthomas.com/2025/01/homepod-hijinks/</guid>
      <pubDate>Thu, 16 Jan 2025 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;When my HomePods aren’t serenading my office with &lt;a href=&quot;https://music.apple.com/us/station/apple-music-chill/ra.1740614260&quot;&gt;the Chill </description>
        
      
      
      
      <content:encoded><![CDATA[<p>When my HomePods aren’t serenading my office with <a href="https://music.apple.com/us/station/apple-music-chill/ra.1740614260">the Chill playlist</a>, keeping me blissfully asleep with nature sounds at night, or fielding my endless Siri queries, they’re also subtly monitoring the environment: Modern HomePod models <a href="https://support.apple.com/en-us/108045#163">include both temperature and humidity sensors</a>, but their values (and thus value) have been constrained to the HomeKit walled garden…but not for long!</p><p>Keen-eyed HomeKit users have likely seen these sensors in their Home apps, but we can extract this data for our own automation purposes…fairly easily, as it turns out! In this post, we’ll unlock access to these sensors via the Shortcuts app and some CLI magic. Stay tuned!</p><h2 id="Shortcut-to-Success"><a href="#Shortcut-to-Success" class="headerlink" title="Shortcut to Success"></a>Shortcut to Success</h2><p>Apple’s <a href="https://support.apple.com/guide/shortcuts/welcome/ios">Shortcuts app</a> is a surprisingly powerful tool for automation, but it’s also a bridge between Apple’s oft-locked-down ecosystem and some of our own custom workflows. Let’s create a simple Shortcut that reads a HomePod’s temperature:</p><img src="/css/images/blog/2025-01-16-01.png" alt="Our simple Shortcut. The nodes included—Get State and Stop and Output—are described below."><p>We need but two Shortcut actions here:</p><ul><li><strong>Get State</strong>. This node will read the value of our HomePod sensor, which you’ll see exposed as “Temperature Sensor” unless you’ve renamed it (which isn’t a bad idea!).</li><li><strong>Stop and Output</strong>. This node does exactly as described: It halts execution of the Shortcut and outputs a given value…here, the temperature! More on this later.</li></ul><p>Save the Shortcut and make note of its name, as we’ll use that next!</p><h2 id="It’s-Terminal-Time"><a href="#It’s-Terminal-Time" class="headerlink" title="It’s Terminal Time!"></a>It’s Terminal Time!</h2><p>The magic happens when we step outside the Shortcuts app and into the CLI: Shortcuts provides a <a href="https://support.apple.com/en-gb/guide/shortcuts-mac/apd455c82f02/mac">conveniently-named <code>shortcuts</code> command</a> to execute a Shortcut via its name.</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">shortcuts run <span class="string">&quot;Read HomePod&quot;</span></span><br></pre></td></tr></table></figure><p>Running the command now, however, produces…not much. The “Stop and Output” action is really designed for running a Shortcut interactively, and <code>shortcuts run</code> prefers a file as output, which doesn’t do our automations any good; however, a <a href="https://www.reddit.com/r/shortcuts/comments/nw4bqe/comment/j13hg6s">helpful Redditor came up with a nifty workaround</a>!</p><p>The Unix <code>tee</code> utility takes its input from <code>STDIN</code> and writes it simultaneously to <code>STDOUT</code> and a file. Serendipitously, piping the output of <code>shortcuts run</code> to <code>tee</code> makes our output visible!</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ shortcuts run <span class="string">&quot;Read HomePod&quot;</span> | <span class="built_in">tee</span></span><br><span class="line"></span><br><span class="line">  20.8°C</span><br></pre></td></tr></table></figure><p>From here, our options are endless! Aside from the obvious geeky satisfaction, programmatically reading data from your HomePods—or any of your HomeKit accessories, for that matter!—can open all kinds of doors. Personally, I have a service that vends these values for my homelab’s dashboard…but that’s another post! Until then, share your favorite Shortcuts and HomeKit hacks in the comments…and happy hacking!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2025/01/homepod-hijinks/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Simplified WordPress Development with Docker Compose</title>
      <link>http://timgthomas.com/2024/01/simplified-wordpress-development-with-docker-compose/</link>
      <guid>http://timgthomas.com/2024/01/simplified-wordpress-development-with-docker-compose/</guid>
      <pubDate>Mon, 15 Jan 2024 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;While not a WordPress developer, I nonetheless find myself occasionally putting together one-off themes and plugins. As a result, it’s ra</description>
        
      
      
      
      <content:encoded><![CDATA[<p>While not a WordPress developer, I nonetheless find myself occasionally putting together one-off themes and plugins. As a result, it’s rarely necessary for me to maintain a full WordPress development environment, but I also want to avoid starting from scratch whenever such a project crosses my desk.</p><p>In this post, we’ll look at using Docker Compose to create a quick way to start building on WordPress plugins and themes that’s both developer- and source control–friendly. Read on to find out more!</p><h2 id="Getting-Started"><a href="#Getting-Started" class="headerlink" title="Getting Started"></a>Getting Started</h2><p>Before starting, you’ll need <a href="https://www.docker.com/get-started/">Docker installed</a> locally. Once installed, the official <a href="https://hub.docker.com/_/mysql/">MySQL</a> and <a href="https://hub.docker.com/_/wordpress/">WordPress Docker images</a> provide an excellent foundation for what we need. We’ll start with a standard Docker Compose configuration; the only points of note are that we’re using a volume for the WordPress database (so we don’t lose any data if we need to recreate the containers), and that we establish a dependency for the WordPress image on the MySQL one (via the <code>depends_on</code> property).</p><p><strong>NOTE</strong>: <em>Please be aware this is</em> absolutely not <em>a production-safe configuration: Its purpose is solely for local development.</em></p><figure class="highlight yml"><table><tr><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3.9&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">wordpress:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">wordpress:latest</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">db</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="comment"># <span class="doctag">NOTE:</span> WordPress will be accessible via port 8000, as defined here.</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&#x27;8000:80&#x27;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">WORDPRESS_DB_HOST:</span> <span class="string">db:3306</span></span><br><span class="line">      <span class="attr">WORDPRESS_DB_USER:</span> <span class="string">wordpress</span></span><br><span class="line">      <span class="attr">WORDPRESS_DB_PASSWORD:</span> <span class="string">wordpress</span></span><br><span class="line">      <span class="attr">WORDPRESS_DB_NAME:</span> <span class="string">wordpress</span></span><br><span class="line">      <span class="attr">WORDPRESS_DEBUG:</span> <span class="number">1</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">db:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">mysql:5.7</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&#x27;3306:3306&#x27;</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">dbdata:/var/lib/mysql</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">MYSQL_ROOT_PASSWORD:</span> <span class="string">somewordpress</span></span><br><span class="line">      <span class="attr">MYSQL_DATABASE:</span> <span class="string">wordpress</span></span><br><span class="line">      <span class="attr">MYSQL_USER:</span> <span class="string">wordpress</span></span><br><span class="line">      <span class="attr">MYSQL_PASSWORD:</span> <span class="string">wordpress</span></span><br><span class="line"></span><br><span class="line"><span class="attr">volumes:</span></span><br><span class="line">  <span class="attr">dbdata:</span></span><br></pre></td></tr></table></figure><p>Once we have the Compose configuration in place, we can get WordPress started:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ docker compose pull</span><br><span class="line">$ docker compose up</span><br></pre></td></tr></table></figure><p>It will take a moment for the images to be pulled and spin up, but once that’s done, visit <code>http://localhost:8000</code> (port 8000 was configured in our Compose configuration file) and go through the WordPress setup. Once that’s complete, we now have a full WordPress instance up and running!</p><h2 id="Adding-Our-Code"><a href="#Adding-Our-Code" class="headerlink" title="Adding Our Code"></a>Adding Our Code</h2><p>Now that we have a running WordPress instance, let’s modify our Compose config to link up our own code. I won’t prescribe a specific folder structure, but this approach has worked well for me: Everything’s grouped in a <code>src</code> folder, within which each theme and plugin has its own folder:</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">- /project</span><br><span class="line">  - /src</span><br><span class="line">    - /example-plugin</span><br><span class="line">      - index.php</span><br><span class="line">  - docker-compose.yml</span><br></pre></td></tr></table></figure><p>We’ll use <a href="https://docs.docker.com/storage/volumes/#use-a-volume-with-docker-compose">Compose’s <code>volumes</code> collection</a> to do the mapping. Note that we’re not mapping the entire <code>plugins</code> folder: Since most WordPress instances use at least some other plugins, it behooves us to map only the plugins we’re working on. This also helps keep the source code clean and focused to just our own code.</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3.9&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">wordpress:</span></span><br><span class="line">    <span class="comment"># Other fields removed for brevity</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./src/example-plugin:/var/www/html/wp-content/plugins/example</span></span><br></pre></td></tr></table></figure><p><a href="https://developer.wordpress.org/plugins/intro/">Creating a WordPress plugin</a> is beyond the scope of this post, but let’s use the following trivial plugin for testing: The plugin’s only “function” is to render a message on each page…just enough for us to verify everything’s working.</p><figure class="highlight php"><table><tr><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Plugin Name: Example Plugin</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="title function_ invoke__">add_action</span>(<span class="string">&#x27;wp_footer&#x27;</span>, <span class="string">&#x27;add_footer&#x27;</span>);</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">add_footer</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">echo</span> <span class="string">&#x27;&lt;p&gt;Hello, world!&lt;/p&gt;&#x27;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Compose won’t be aware of our new volume mapping until the service is stopped and restarted (a normal <code>restart</code> command isn’t sufficient):</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ docker compose stop</span><br><span class="line">$ docker compose up</span><br></pre></td></tr></table></figure><p>Once the containers are running again, take a peek at your instance’s plugins page at <code>http://localhost:8000/wp-admin/plugins.php</code>. If all went well, you should see our new plugin in the list! Just click “Activate” and verify everything works by visiting any page of your WordPress instance and scrolling to the bottom.</p><h2 id="Next-Steps"><a href="#Next-Steps" class="headerlink" title="Next Steps"></a>Next Steps</h2><p>Though we’ve just demonstrated plugin development in this post, the same procedure applies for themes, as well: Just map your theme to <code>/var/www/html/wp-content/themes/&lt;theme&gt;</code>. Don’t forget to activate it!</p><p>If you’d like a jumping-off point, <a href="https://github.com/timgthomas/blog-wordpress-docker-compose">the code for this post is available on GitHub</a>. Happy coding with WordPress!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2024/01/simplified-wordpress-development-with-docker-compose/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Advanced Alpine.js, Part II: Moving Beyond HTML</title>
      <link>http://timgthomas.com/2021/12/advanced-alpine-js-part-2/</link>
      <guid>http://timgthomas.com/2021/12/advanced-alpine-js-part-2/</guid>
      <pubDate>Tue, 14 Dec 2021 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;h2 id=&quot;Posts-in-This-Series&quot;&gt;&lt;a href=&quot;#Posts-in-This-Series&quot; class=&quot;headerlink&quot; title=&quot;Posts in This Series&quot;&gt;&lt;/a&gt;Posts in This Series&lt;/h2&gt;&lt;</description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="Posts-in-This-Series"><a href="#Posts-in-This-Series" class="headerlink" title="Posts in This Series"></a>Posts in This Series</h2><dl>  <dt><a href="/2021/12/advanced-alpine-js-part-1/">Part I: The Story So Far</a></dt>  <dd>In which we review some basics about Alpine.js</dd>  <dt>Part II: Moving Beyond HTML (This post)</dt>  <dd>In which we refactor our app and add filtering</dd>  <dt>Part III</dt>  <dd>Coming soon!</dd>  <dt>Part IV</dt>  <dd>Coming soon!</dd>  <dt>Part V</dt>  <dd>Coming soon!</dd></dl><p>In this series, we’ve been building a music playlist app using some modern workflows and Alpine.js features. Today, we’ll add a quality-of-life improvement for our users and get to know some of Alpine’s more advanced features. We’ll start by moving and refactoring our inline code into a separate JavaScript file, then add filtering so users can more easily navigate through the 250+ playlists. Let’s get started!</p><h2 id="Moving-Beyond-HTML"><a href="#Moving-Beyond-HTML" class="headerlink" title="Moving Beyond HTML"></a>Moving Beyond HTML</h2><p>Up to this point, we’ve used Alpine’s expressive inline code directives for all the behavior in our app. Though this is a perfectly fine way to continue, reading JavaScript <em>inside</em> HTML attributes gets more and more difficult over time. If you’re working with Alpine’s inline scripts in production, I’d encourage you to frequently revisit whether it’s time to move to a more formal script file. For our playlists app, now is that time!</p><p>Alpine provides a convenient global for injecting our formerly-inline scripts into its runtime, as well as a global <code>document</code> event so we can ensure it’s completely loaded before attempting to do so:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;alpine:init&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// We have access to `window.Alpine` here to add our logic</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>At this point, though, we have a choice of how to proceed: Continuing to use a <a href="https://alpinejs.dev/globals/alpine-data"><code>data</code></a> object, or upgrading to a <a href="https://alpinejs.dev/globals/alpine-store"><code>store</code></a>. These two concepts are fairly similar, and use nearly-identical APIs, supporting properties, functions, etc. The main difference is that Stores are globally-accessible in Alpine apps (via the <a href="https://alpinejs.dev/magics/store"><code>$store</code></a> variable), while Data objects are designed to be more tightly-scoped and flexible.</p><p>Our straightforward app could quite easily rely on either approach, but we’ll take this opportunity to add a Store. In your apps, this is a great opportunity to think about whether you need to reuse these services, and how much of your app they affect. Logic included in specific parts of your app (think widgets, cards, and the like) are well-served by Data objects, while tracking global state like a user’s authentication status and preferences work well with Stores.</p><p>Okay, back to some code! After creating our new script file, let’s create a Store and add some basic functionality. In part one, we used <a href="https://lodash.com/">Lodash</a> and a <code>window</code> global to group our playlists by a given property. We could continue to use Lodash’s response format (a single object with one key per group), but I think a proper array is more understandable, so we’ll dip into the native <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries"><code>Object.entries()</code></a> function to clean that up, as well:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;alpine:init&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// Note the Store&#x27;s name of &quot;app&quot;, which we&#x27;ll reference in the HTML.</span></span><br><span class="line">  <span class="title class_">Alpine</span>.<span class="title function_">store</span>(<span class="string">&#x27;app&#x27;</span>, &#123;</span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">groupedPlaylists</span>() &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="title class_">Object</span></span><br><span class="line">        .<span class="title function_">entries</span>(_.<span class="title function_">groupBy</span>(<span class="variable language_">window</span>.<span class="property">data</span>, <span class="string">&#x27;group&#x27;</span>))</span><br><span class="line">        .<span class="title function_">map</span>(<span class="function">(<span class="params">[ groupName, playlists ]</span>) =&gt;</span> (&#123;</span><br><span class="line">          groupName, playlists</span><br><span class="line">        &#125;))</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>We also need to update the HTML directives to reference our nascent Store. Our wrapper <code>&lt;template&gt;</code> tag now looks like this:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="comment">&lt;!-- `$store.app` is how we reference our Store by name. --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">template</span></span></span><br><span class="line"><span class="tag">  <span class="attr">x-for</span>=<span class="string">&quot;group of $store.app.groupedPlaylists&quot;</span></span></span><br><span class="line"><span class="tag">  <span class="attr">:key</span>=<span class="string">&quot;group.groupName&quot;</span></span></span><br><span class="line"><span class="tag">&gt;</span></span><br><span class="line">  <span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">    References to `groupName` and `playlists` need to be updated to</span></span><br><span class="line"><span class="comment">    use `group.`, as well.</span></span><br><span class="line"><span class="comment">  --&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Hopefully you can already see the benefits of a separate script file: Putting our multi-step conversion from an object literal into an array of objects would be quite confusing to try to read in the middle of an HTML attribute, and that’s even assuming syntax highlighting works!</p><p>Now that we have a great place for more complex logic, let’s add some!</p><h2 id="Our-Feature-Presentation"><a href="#Our-Feature-Presentation" class="headerlink" title="Our Feature Presentation"></a>Our Feature Presentation</h2><p>The first feature we’re going to add to our app is filtering. Our playlists collection comprises over 250 items, which is a lot to scroll through! Adding a quick filter would really help our users narrow down the potential mood playlists they can listen to. The Alpine docs already contain <a href="https://alpinejs.dev/start-here#building-a-search-input">a tutorial on building a search input</a>, so I won’t go into too much detail on how to build one, but the code is quite clear, regardless.</p><p>There are two behaviors I’d like to highlight, however: One, we’d still like our playlists grouped after they’re filtered, so we’re going to update the <code>groupedPlaylists</code> property to group the <em>filtered</em> list instead of the complete one; and two, since we’re using each playlist’s <code>slug</code>, we need to replace any hyphens with blank spaces in case a user searches a string like “chilling out”. The latter is easily accomplished with a regular expression.</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Alpine</span>.<span class="title function_">store</span>(<span class="string">&#x27;app&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">filter</span>: <span class="string">&#x27;&#x27;</span>, <span class="comment">// This property will be bound to an HTML &lt;input&gt;</span></span><br><span class="line">  <span class="keyword">get</span> <span class="title function_">filteredPlaylists</span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> filterString = <span class="variable language_">this</span>.<span class="property">filter</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">trim</span>()</span><br><span class="line"></span><br><span class="line">    <span class="comment">// If the user hasn&#x27;t entered text, return all playlists</span></span><br><span class="line">    <span class="keyword">if</span> (filterString === <span class="string">&#x27;&#x27;</span>) <span class="keyword">return</span> <span class="variable language_">window</span>.<span class="property">data</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// Otherwise, perform the basic &quot;search&quot; by playlist name</span></span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">window</span>.<span class="property">data</span>.<span class="title function_">filter</span>(<span class="function">(<span class="params">playlist</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">let</span> playlistName = playlist.<span class="property">slug</span>.<span class="title function_">replace</span>(<span class="regexp">/-/g</span>, <span class="string">&#x27; &#x27;</span>)</span><br><span class="line">      <span class="keyword">return</span> playlistName.<span class="title function_">includes</span>(filterString)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="keyword">get</span> <span class="title function_">groupedPlaylists</span>() &#123;</span><br><span class="line">    <span class="comment">// This property remains mostly the same, but we&#x27;ll replace</span></span><br><span class="line">    <span class="comment">// `window.data` with `this.filteredPlaylists`.</span></span><br><span class="line">  &#125;,</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>As you might expect with a modern JavaScript library, Alpine handles all the <a href="https://alpinejs.dev/advanced/reactivity">reactivity</a> for us! Just referencing <code>this.filter</code> and friends automatically re-evaluates each property whenever the upstream values change.</p><p>At this point, we could play around with the <code>filter</code> property to make sure the searching works, but it’s so easy to add the <code>&lt;input&gt;</code> so users can perform the filter that we may as well! We’ll add the search filter input into the page’s <code>&lt;header&gt;</code>; if you’ve been following along with the HTML, you’ll know that only our <code>&lt;ul&gt;</code> is “Alpine-aware” via a <code>x-data</code> attribute, so we can either add <code>x-data</code> to the header element, or the HTML <code>&lt;body&gt;</code> itself. I’ve chosen the latter, since this entire page now is one big app!</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span> <span class="attr">x-data</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">header</span> <span class="attr">role</span>=<span class="string">&quot;banner&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;constrained&quot;</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">h1</span>&gt;</span>Apple Mood Playlists<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">      <span class="comment">&lt;!-- Note the `$store.app` prefix is here, as well. --&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">input</span> <span class="attr">x-model</span>=<span class="string">&quot;$store.app.filter&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;Search&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">header</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- ... --&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure><p>We now have a nice quick filter input that searches playlist names, and thanks to our updates to the <code>groupedPlaylist</code> property, we don’t even have to deal with empty groups! If you’re feeling adventurous, though, a great UX improvement would be to display a “no results” message, but I’ll leave that as an exercise to the reader.</p><p><img src="/2021/12/advanced-alpine-js-part-2/0-filtering.png" alt="The running app with filtering working"></p><h2 id="Until-Next-Time"><a href="#Until-Next-Time" class="headerlink" title="Until Next Time!"></a>Until Next Time!</h2><p>In this post, we refactored Alpine’s inline HTML directives into a separate script file, and added a quick filter so users can easily find playlists. Filtering is a great start to improving our app’s user experience, but we can go further: Allowing users to “favorite” mood playlists is a fantastic way to make our app even more usable! Stop by in our next post when we do just that, and we’ll look at another nifty component of Alpine while we’re at it. Happy listening!</p><h3 id="Resources-in-this-post"><a href="#Resources-in-this-post" class="headerlink" title="Resources in this post"></a>Resources in this post</h3><ul><li><a href="https://github.com/timgthomas/apple-playlists/tree/main/blog/part-2">Source code for Part II (GitHub)</a></li></ul>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2021/12/advanced-alpine-js-part-2/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Advanced Alpine.js, Part I: The Story So Far</title>
      <link>http://timgthomas.com/2021/12/advanced-alpine-js-part-1/</link>
      <guid>http://timgthomas.com/2021/12/advanced-alpine-js-part-1/</guid>
      <pubDate>Tue, 07 Dec 2021 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;h2 id=&quot;Posts-in-This-Series&quot;&gt;&lt;a href=&quot;#Posts-in-This-Series&quot; class=&quot;headerlink&quot; title=&quot;Posts in This Series&quot;&gt;&lt;/a&gt;Posts in This Series&lt;/h2&gt;&lt;</description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="Posts-in-This-Series"><a href="#Posts-in-This-Series" class="headerlink" title="Posts in This Series"></a>Posts in This Series</h2><dl>  <dt>Part I: The Story So Far (This post)</dt>  <dd>In which we review some basics about Alpine.js</dd>  <dt><a href="/2021/12/advanced-alpine-js-part-2/">Part II: Moving Beyond HTML</a></dt>  <dd>In which we refactor our app and add filtering</dd>  <dt>Part III</dt>  <dd>Coming soon!</dd>  <dt>Part IV</dt>  <dd>Coming soon!</dd>  <dt>Part V</dt>  <dd>Coming soon!</dd></dl><p>Recently, I’ve been spending a lot of time with <a href="https://alpinejs.dev/">Alpine.js</a>, a self-proclaimed “rugged, minimal” JavaScript tool that sprinkles behavior on top of rendered HTML. This is the kind of technology I wished for—and <a href="https://github.com/timgthomas/illustractions">briefly experimented with</a>—in the bygone days of back-end-language-rendered HTML before single-page apps became the norm. Though Alpine isn’t as full-featured as other frameworks, I’ve found it refreshingly easy to work with, and perfect for proof-of-concept apps.</p><p>In this series, we’ll look at some advanced workflows with Alpine by building out a music playlist app. We’ll start by setting up Alpine (a shockingly trivial thing to do), then add some features, a build system, and finally, some testing. The final code is <a href="https://github.com/timgthomas/apple-playlists/blob/main/blog/part-1/index.html">available on GitHub</a> if you’d like to take a peek before we begin. Let’s dive in!</p><h2 id="What-we’re-building"><a href="#What-we’re-building" class="headerlink" title="What we’re building"></a>What we’re building</h2><p>Like many developers, I love listening to music while I code. Also like many developers, I hate being interrupted while I’m focused…like when I need to find a new album to listen to after the current one ends, for example. Thankfully, playlists have been part of the streaming music streaming since the very beginning, and solve this problem nicely. Recently, <a href="https://www.apple.com/newsroom/2021/10/apple-introduces-the-apple-music-voice-plan/">Apple announced</a> some curated (and constantly-updated) playlists for “moods”, and I’ve been a huge fan of every one I’ve listened to.</p><p>Unfortunately, as of this writing, Apple hasn’t <em>published</em> this list, and their discoverability is limited to asking Siri to “play the dinner party playlist”. Thankfully, MacStories took the initiative to <a href="https://www.macstories.net/stories/a-comprehensive-guide-to-250-of-apple-musics-new-mood-and-activity-playlists/">document as many as they could find</a>, but we can do better!</p><p>Our Alpine app will display these playlists, roughly categorized (thanks again to MacStories for the grouping), but also allow us to search for playlists and “favorite” some so we can easily find them later.</p><p><img src="/2021/12/advanced-alpine-js-part-1/0-preview.png" alt="A preview of the finished app from this post"></p><h2 id="An-Alpine-Climb"><a href="#An-Alpine-Climb" class="headerlink" title="An Alpine Climb"></a>An Alpine Climb</h2><p>If you’re brand-new to Alpine, I strongly suggest <a href="https://alpinejs.dev/start-here">working through their tutorials</a>. It’s quite remarkable how trivial it is to get started with Alpine: A single <code>&lt;script&gt;</code> tag is really all you need!</p><p>For our app, we’ll start with just two files: An HTML page and a JavaScript file containing a static list of the playlists (there are just over 250 of them, so this helps keep our other code clean). Following the conventions of the Alpine docs, our HTML file looks something like this:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">script</span> <span class="attr">defer</span> <span class="attr">src</span>=<span class="string">&quot;https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!-- Our markup will live here... --&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;./data.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="comment">// ...and our behavior, here!</span></span></span><br><span class="line"><span class="language-javascript">  </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>The data file creates a global variable for the playlists that we can reference from the app. Though global variables aren’t a good practice, this one will work for for the moment, and we’ll fix this issue in a later part of this series.</p><p>For this app, we’ll need two pieces of information to uniquely identify each playlist (an ID and a slug, which I’ve pulled from each playlist’s URL), as well as a group name (again, from the general grouping provided by MacStories):</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">data</span> = [</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">id</span>: <span class="string">&#x27;163ac0d163734b888fb6490db5520094&#x27;</span>,</span><br><span class="line">    <span class="attr">slug</span>: <span class="string">&#x27;spring&#x27;</span>,</span><br><span class="line">    <span class="attr">group</span>: <span class="string">&#x27;Seasons and Weather&#x27;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">id</span>: <span class="string">&#x27;9d61a50fbc9c42a9b5eb5df3eb763d0c&#x27;</span>,</span><br><span class="line">    <span class="attr">slug</span>: <span class="string">&#x27;summer&#x27;</span>,</span><br><span class="line">    <span class="attr">group</span>: <span class="string">&#x27;Seasons and Weather&#x27;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">id</span>: <span class="string">&#x27;b04a92a765114f8691c08ff96f57ed57&#x27;</span>,</span><br><span class="line">    <span class="attr">slug</span>: <span class="string">&#x27;fall&#x27;</span>,</span><br><span class="line">    <span class="attr">group</span>: <span class="string">&#x27;Seasons and Weather&#x27;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">id</span>: <span class="string">&#x27;8b36c21d1ce7493392a2f845c4293408&#x27;</span>,</span><br><span class="line">    <span class="attr">slug</span>: <span class="string">&#x27;winter&#x27;</span>,</span><br><span class="line">    <span class="attr">group</span>: <span class="string">&#x27;Seasons and Weather&#x27;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">]</span><br></pre></td></tr></table></figure><h2 id="Listing-the-Playlists"><a href="#Listing-the-Playlists" class="headerlink" title="Listing the Playlists"></a>Listing the Playlists</h2><p>We’ll start building the app proper by showing a basic list of each playlist, and adding URLs so they can be clicked to open each playlist in Apple Music. We’ll use a combination of Alpine’s <a href="https://alpinejs.dev/directives/data"><code>x-data</code></a>, <a href="https://alpinejs.dev/directives/for"><code>x-for</code></a>, and <a href="https://alpinejs.dev/directives/text"><code>x-text</code></a> directives to render a list of each playlist’s slug:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">ul</span> <span class="attr">x-data</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">template</span> <span class="attr">x-for</span>=<span class="string">&quot;playlist in window.data&quot;</span> <span class="attr">:key</span>=<span class="string">&quot;playlist.id&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">x-text</span>=<span class="string">&quot;playlist.slug&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Alpine uses <code>x-data</code> to identify which parts of the page require interactivity, so we’ll add that to our <code>&lt;ul&gt;</code>, even though we’re referencing the playlist array directly in the <code>x-for</code> directive. You could also add a proxy variable inside <code>x-data</code> if you choose (i.e. <code>&lt;ul x-data=&quot;&#123; playlists: window.data &#125;&quot;&gt;</code>), which is a testament to Alpine’s flexibility when integrating with existing HTML.</p><p>Just showing playlists’ slugs isn’t very useful, so let’s add links so users can open each playlist. For this, we’ll use the <a href="https://alpinejs.dev/directives/bind"><code>x-bind</code></a> directive (more accurately, its shorthand of <code>:&lt;attribute&gt;</code>) to populate each playlist’s <code>href</code> attribute. Alpine lets us use plain JavaScript expressions (be sure to <a href="https://alpinejs.dev/advanced/csp">read up on the security implications</a>), so a string interpolation to translate a playlist’s ID and slug into a correct URL is straightforward:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">    <span class="attr">:href</span>=<span class="string">&quot;`https://music.apple.com/us/playlist/$&#123;playlist.slug&#125;/pl.$&#123;playlist.id&#125;`&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">x-text</span>=<span class="string">&quot;playlist.slug&quot;</span></span></span><br><span class="line"><span class="tag">  &gt;</span><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Of course, a flat list of 250+ playlist slugs isn’t a great experience, but to improve that, we’re going to need a little help…</p><p><img src="/2021/12/advanced-alpine-js-part-1/1-playlists.png" alt="Our progress: Showing 250+ playlist slugs and links"></p><h2 id="Lo-Dashing-up-the-Mountain"><a href="#Lo-Dashing-up-the-Mountain" class="headerlink" title="(Lo)Dashing up the Mountain"></a>(Lo)Dashing up the Mountain</h2><p>Lodash is a <a href="https://lodash.com/">fantastic utility library</a> that comprises a large number of useful functions. It’s worthy of its own blog series, but we’re going to use only two of its many helpers: <a href="https://lodash.com/docs/4.17.15#startCase"><code>startCase()</code></a>, which converts a slug into something more human-readable, and <a href="https://lodash.com/docs/4.17.15#groupBy"><code>groupBy()</code></a>, which, well, <em>groups</em> the playlists <em>by</em> a given key (in our case, we’re using <code>group</code>).</p><p>Adding Lodash to our app is as simple as inserting another <code>&lt;script&gt;</code> tag into our <code>&lt;head&gt;</code>; we can use the same CDN as Alpine itself:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://unpkg.com/lodash@4.x.x/lodash.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>…and humanizing our slugs is nearly as straightforward:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">    <span class="attr">:href</span>=<span class="string">&quot;...&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">x-text</span>=<span class="string">&quot;_.startCase(playlist.slug)&quot;</span></span></span><br><span class="line"><span class="tag">  &gt;</span><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Grouping the playlists is slightly more complex, but only just. Lodash’s <code>groupBy()</code> function’s return value is an object with the group names as keys; for example, our example data from above would get grouped thusly:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&#123; <span class="string">&#x27;Seasons and Weather&#x27;</span>: [ &#123; ... &#125;, &#123; ... &#125;, &#123; ... &#125;, &#123; ... &#125; ] &#125;</span><br></pre></td></tr></table></figure><p>Built-in functions like <code>Object.entries()</code> could help us out here by converting this object to an array, but I’ve found Alpine is capable of iterating objects on its own. Be warned, though: I haven’t found any official documentation suggesting this is a supported feature, so it’s possible it will break in future releases, or behave strangely. That said, we can use a similar template as we’ve used above for the groups:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">ul</span> <span class="attr">x-data</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">template</span></span></span><br><span class="line"><span class="tag">    <span class="attr">x-for</span>=<span class="string">&quot;(playlists, groupName) of _.groupBy(window.data, &#x27;group&#x27;)&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">:key</span>=<span class="string">&quot;groupName&quot;</span></span></span><br><span class="line"><span class="tag">  &gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span> <span class="attr">x-text</span>=<span class="string">&quot;groupName&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Ah, but now we have a list of 250+ playlists <em>and</em> a list of about twenty groups. So how can we put the two together? Spoiler alert: Quite easily! We can nest the <code>x-for</code> for the playlists (and its associated <code>&lt;template&gt;</code>) <em>inside</em> the one for the grouping:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">ul</span> <span class="attr">x-data</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">template</span></span></span><br><span class="line"><span class="tag">    <span class="attr">x-for</span>=<span class="string">&quot;(playlists, groupName) of _.groupBy(window.data, &#x27;group&#x27;)&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">:key</span>=<span class="string">&quot;groupName&quot;</span></span></span><br><span class="line"><span class="tag">  &gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">h1</span> <span class="attr">x-text</span>=<span class="string">&quot;groupName&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">template</span> <span class="attr">x-for</span>=<span class="string">&quot;playlist in playlists&quot;</span> <span class="attr">:key</span>=<span class="string">&quot;playlist.id&quot;</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">              <span class="attr">:href</span>=<span class="string">&quot;`https://music.apple.com/us/playlist/$&#123;playlist.slug&#125;/pl.$&#123;playlist.id&#125;`&quot;</span></span></span><br><span class="line"><span class="tag">              <span class="attr">x-text</span>=<span class="string">&quot;_.startCase(playlist.slug)&quot;</span></span></span><br><span class="line"><span class="tag">            &gt;</span><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br></pre></td></tr></table></figure><p>We’ve now got a lovely nested list of grouped playlists and the playlists themselves:</p><p><img src="/2021/12/advanced-alpine-js-part-1/2-grouping.png" alt="More progress: Showing groups of playlists"></p><p>Throw in a bit of styling, and we have ourselves a great mini-app for finding our favorite Apple “mood” playlists! If you’ve been following along, you may have noticed something interesting: Excepting the data file and the sprinkling of Alpine code, this app contains zero JavaScript! Everything’s done within Alpine’s directives.</p><p><img src="/2021/12/advanced-alpine-js-part-1/0-preview.png" alt="The finished app from this post"></p><h2 id="Next-Up-More-Features"><a href="#Next-Up-More-Features" class="headerlink" title="Next Up: More Features!"></a>Next Up: More Features!</h2><p>In the next post in the series, we’ll expand our simple app with some quality-of-life features: Filtering the playlists by name, and “favoriting” some so we can easily get back to our most-loved moods. Until next time!</p><h3 id="Resources-in-this-post"><a href="#Resources-in-this-post" class="headerlink" title="Resources in this post"></a>Resources in this post</h3><ul><li><a href="https://alpinejs.dev/">Alpine.js docs</a></li><li><a href="https://lodash.com/">Lodash docs</a></li><li><a href="https://github.com/timgthomas/apple-playlists/blob/main/blog/part-1/index.html">Source code for Part I (GitHub)</a></li></ul>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2021/12/advanced-alpine-js-part-1/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Unit-testing Glimmer Components</title>
      <link>http://timgthomas.com/2019/11/unit-testing-glimmer-components/</link>
      <guid>http://timgthomas.com/2019/11/unit-testing-glimmer-components/</guid>
      <pubDate>Thu, 07 Nov 2019 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;&lt;em&gt;Update: Some amazing sleuthing by Discord user DanDan has not only uncovered breaking API changes, but also cleaned up some of the co</description>
        
      
      
      
      <content:encoded><![CDATA[<p><em>Update: Some amazing sleuthing by Discord user DanDan has not only uncovered breaking API changes, but also cleaned up some of the component manager lookup code. Thanks so much, DanDan!</em></p><p>Like many Ember developers, I’m excited about <a href="https://glimmerjs.com/">Glimmer</a>. With the <a href="https://emberjs.com/editions/octane/">Octane</a> release, the Ember team has removed a lot of cruft from the framework and dramatically simplified day-to-day development. As such, I was excited to upgrade to the latest releases that support Glimmer—3.13 and 3.14—and try out the new goodies.</p><p>Unfortunately, I quickly ran into what seemed like a strange miss on Glimmer’s part: Glimmer components don’t appear to support unit tests. Most of my Ember projects use a large number of component unit tests, so this was a bummer to discover: I’d have to make major changes to the way my components worked in order to have test coverage.</p><h2 id="The-Problem"><a href="#The-Problem" class="headerlink" title="The Problem"></a>The Problem</h2><p>A default component unit test (created via <code>ember generate</code>) looks something like this:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title function_">test</span>(<span class="string">&#x27;it exists&#x27;</span>, <span class="keyword">function</span>(<span class="params">assert</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> component = <span class="variable language_">this</span>.<span class="property">owner</span>.<span class="title function_">factoryFor</span>(<span class="string">&#x27;component:my-component&#x27;</span>).<span class="title function_">create</span>();</span><br><span class="line">  assert.<span class="title function_">ok</span>(component);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>This test is pretty easy to understand: the test looks up the factory function for the component we specify, then creates an instance, returning a reference so we can make assertions against the component, minus its rendering. I use this kind of test all the time to exercise computed properties, so I naturally started here when looking to test Glimmer components.</p><p>Running said test, however, provided the following error:</p><blockquote><p>Error: Failed to create an instance of ‘component:my-component’. Most likely an improperly defined class or an invalid module export.</p></blockquote><p>I asked around on <a href="https://discord.gg/emberjs">Ember’s Discord</a> (a great place to get help, if you haven’t discovered this already), but there was no obvious solution. I tried a couple of other suggested options, all to no avail:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title function_">new</span> (<span class="variable language_">this</span>.<span class="property">owner</span>.<span class="title function_">factoryFor</span>(<span class="string">&#x27;component:my-component&#x27;</span>).<span class="property">class</span>);</span><br><span class="line"><span class="keyword">new</span> <span class="title class_">MyComponent</span>(<span class="variable language_">this</span>.<span class="property">owner</span>.<span class="title function_">ownerInjection</span>(), &#123;&#125;);</span><br></pre></td></tr></table></figure><blockquote><p>Error: You must pass both the owner and args to super() in your component.</p></blockquote><p>What I <em>was</em> provided with, though, was some background on Glimmer’s internals and some discussion on component testing in general: just enough to get the <a href="https://en.wikipedia.org/wiki/Hercule_Poirot">little grey cells</a> moving.</p><h2 id="To-the-source"><a href="#To-the-source" class="headerlink" title="To the source!"></a>To the source!</h2><p>Fortunately, Glimmer’s source (and Ember’s, too, really) is very readable, and it didn’t take long to grok how Glimmer’s components work: arguments passed to components are given to a <a href="https://github.com/glimmerjs/glimmer.js/blob/master/packages/%40glimmer/component/addon/-private/ember-component-manager.ts">ComponentManager</a>, which then passes them to newly-created <a href="https://github.com/glimmerjs/glimmer.js/blob/master/packages/%40glimmer/component/addon/-private/component.ts">Component</a>s after confirming that the args’ integrity is intact. Can we then use this same approach to create components for unit testing? In short: yes!</p><p><strong>The Owner.</strong> First, we’ll need a reference to the “owner”: a shortcut into <a href="https://guides.emberjs.com/release/applications/dependency-injection/">Ember’s dependency injection container</a>. If we’re already inside a test, we can access this via <code>this.owner</code>; otherwise, we can use a function from <a href="https://github.com/emberjs/ember-test-helpers/blob/master/API.md#getcontext"><code>@ember/test-helpers</code></a>:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; getContext &#125; <span class="keyword">from</span> <span class="string">&#x27;@ember/test-helpers&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> &#123; owner &#125; = <span class="title function_">getContext</span>();</span><br></pre></td></tr></table></figure><p><strong>The Factory.</strong> We also need a factory function to give to the Component Manager so it can create the Component instance. Historically, this was in a <a href="https://api.emberjs.com/ember/3.14/classes/ApplicationInstance/methods/factoryFor"><code>factoryFor()</code></a> function, and it still is: just behind a <code>class</code> property (since we’re using classes now!). To get this, we’ll need the lookup key for the component (usually of the style of <code>component:my-component</code>). If you’re migrating an existing unit test, this is the string passed to <code>factoryFor()</code>:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> lookupPath = <span class="string">&#x27;component:my-component&#x27;</span>;</span><br><span class="line"><span class="keyword">let</span> &#123; <span class="attr">class</span>: componentClass &#125; = owner.<span class="title function_">factoryFor</span>(lookupPath);</span><br></pre></td></tr></table></figure><p><strong>The Component Manager.</strong> Next, we need to create the aforementioned Component Manager, through which we’ll pass arguments to our soon-to-be-created component. The component manager is injected into Ember’s dependency container, so we can import it thusly:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> componentManager = owner.<span class="title function_">lookup</span>(<span class="string">&#x27;component-manager:glimmer&#x27;</span>);</span><br></pre></td></tr></table></figure><p><strong>At last: the Component!</strong> Now that we have an Owner and Component Manager, we can create the component we’ve always wanted! We’ll need one last thing: any arguments we want to provide the Component. The Component Manager expects these <a href="https://github.com/glimmerjs/glimmer.js/blob/master/packages/%40glimmer/component/addon/-private/ember-component-manager.ts#L74">in an attribute named <code>named</code></a>, so we’ll oblige it:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> named = &#123; <span class="attr">myArgument</span>: <span class="number">42</span> &#125;;</span><br><span class="line"><span class="keyword">let</span> component = componentManager.<span class="title function_">createComponent</span>(componentClass, &#123; named &#125;);</span><br></pre></td></tr></table></figure><p><strong>The Tests.</strong> The component alone is not enough, of course: we still need our tests. I was concerned about this part, because Glimmer components <a href="https://emberjs.github.io/rfcs/0410-tracked-properties.html">do away with computed properties and Ember’s getters and setters</a>. I needn’t have worried, though: Octane’s changes mean most Glimmer component code is regular JavaScript! Just set values as you would inside the Glimmer component, and you’re all good!</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">named.<span class="property">myArgument</span> = <span class="number">1337</span>;</span><br><span class="line">assert.<span class="title function_">equal</span>(component.<span class="property">someGetterThatUsesMyArgument</span>, <span class="number">1337</span>);</span><br></pre></td></tr></table></figure><h2 id="Don’t-Repeat-Yourself"><a href="#Don’t-Repeat-Yourself" class="headerlink" title="Don’t Repeat Yourself"></a>Don’t Repeat Yourself</h2><p>I use this approach often enough that I usually create a test helper to do all the hard work for us in one place. Here’s the helper in its entirety:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; getContext &#125; <span class="keyword">from</span> <span class="string">&#x27;@ember/test-helpers&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">createComponent</span>(<span class="params">lookupPath, named = &#123;&#125;</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> &#123; owner &#125; = <span class="title function_">getContext</span>();</span><br><span class="line">  <span class="keyword">let</span> componentManager = owner.<span class="title function_">lookup</span>(<span class="string">&#x27;component-manager:glimmer&#x27;</span>);</span><br><span class="line">  <span class="keyword">let</span> &#123; <span class="attr">class</span>: componentClass &#125; = owner.<span class="title function_">factoryFor</span>(lookupPath);</span><br><span class="line">  <span class="keyword">return</span> componentManager.<span class="title function_">createComponent</span>(componentClass, &#123; named &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>And you can use it thusly:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> createComponent <span class="keyword">from</span> <span class="string">&#x27;my-app/tests/helpers/create-component&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="title function_">test</span>(<span class="string">&#x27;should calculate the value&#x27;</span>, <span class="keyword">async</span> <span class="keyword">function</span>(<span class="params">assert</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> model = &#123; <span class="attr">val</span>: <span class="number">4</span> &#125;;</span><br><span class="line">  <span class="keyword">let</span> component = <span class="title function_">createComponent</span>(<span class="string">&#x27;component:my-component&#x27;</span>, &#123; model &#125;);</span><br><span class="line">  assert.<span class="title function_">equal</span>(component.<span class="property">valueSquared</span>, <span class="number">16</span>);</span><br><span class="line"></span><br><span class="line">  model.<span class="property">val</span> = <span class="number">3</span>;</span><br><span class="line">  assert.<span class="title function_">equal</span>(component.<span class="property">valueSquared</span>, <span class="number">9</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>I’ve published a <a href="https://github.com/timgthomas/unit-testing-glimmer-components">sample Ember Octane app on GitHub</a> if you’d like to play around with real code.</p><h2 id="A-Disclaimer"><a href="#A-Disclaimer" class="headerlink" title="A Disclaimer"></a>A Disclaimer</h2><p>As I mentioned earlier in this post, Octane doesn’t officially support unit tests for Glimmer components. Although (as far as I can tell), everything in this post uses non-private APIs, there’s no guarantee this approach will work in the future. Of course, I hope the Ember and Glimmer teams restore official support for this type of test, as it’s usually the first thing I reach for when building out components. Until then, I’ll try to keep up with any API changes and update this post to match.</p><hr><p>I want to extend special thanks to <a href="https://twitter.com/nullvoxpopuli">NullVoxPopuli</a>, <a href="https://www.pzuraq.com/">pzuraq</a>, and <a href="https://twitter.com/bendemboski">bendemboski</a> from the Discord server, for listening to my concerns, patiently explaining me through the Glimmer rendering process, and offering suggestions on how to proceed.</p><p>I also owe Discord user DanDan a debt of gratitude for letting me know of the breaking Glimmer API and his work to resolve it. Much appreciated!</p><p>Do you have any other approaches you use for component tests? Suggestions for improvement? Let me know in the comments below, and happy testing!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2019/11/unit-testing-glimmer-components/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Upstaging Upsetting Upstreams</title>
      <link>http://timgthomas.com/2019/07/upstaging-upsetting-upstreams/</link>
      <guid>http://timgthomas.com/2019/07/upstaging-upsetting-upstreams/</guid>
      <pubDate>Tue, 09 Jul 2019 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;Many browser requests communicate directly with one server: the client needs to grab or update data, or perhaps perform an action like lo</description>
        
      
      
      
      <content:encoded><![CDATA[<p>Many browser requests communicate directly with one server: the client needs to grab or update data, or perhaps perform an action like logging in. Sometimes, though, you need to chat with sources upstream of even your own resource: passing an API token to a third party service, for example. In these situations, response status codes can quickly get out of hand. Do you return the upstream status code? Your own? A combination of the two?</p><p>One option is to simply pass along the upstream status code to the client: if your server can’t login to another server, for instance, return the second box’s <code>4XX</code>.</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// HTTP 401 Not Authorized</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;response&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;error&quot;</span>: <span class="string">&quot;Your credentials were invalid&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Unfortunately, this introduces some confusion to the consuming code: did <em>your</em> server reject the request, or did the upstream one do so?</p><p>The solution that has worked well for us is to wrap the upstream request before sending it to the client. In other words, <em>your</em> server should return its own status code, but <em>contain</em> the upstream one. Philosophically, if the request to <em>your</em> server succeeds, still consider the request “successful” (with a <code>200</code>) even if the upstream errors (a <code>404</code>, for example).</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// HTTP 200 OK</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;upstreamResponse&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;statusCode&quot;</span>: <span class="number">401</span>,</span><br><span class="line">    <span class="string">&quot;error&quot;</span>: <span class="string">&quot;Your credentials were invalid&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This allows us to both represent <em>our</em> system’s status (where a <code>401</code> may represent that a user isn’t logged in for us) and the <em>upstream’s</em> status (where a <code>401</code> may be completely unrelated to our own authentication system). It’s helpful to include both for user experience purposes, as you can easily differentiate to users whether it’s your code or someone else’s that threw an exception.</p><p>This behavior is nuanced, but we’ve found it effectively represents disparate servers’ statuses. Have you had similar results? Is there a solution that works better for you? Weigh in in the comments!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2019/07/upstaging-upsetting-upstreams/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>New Year, New Monospace</title>
      <link>http://timgthomas.com/2018/01/new-year-new-monospace/</link>
      <guid>http://timgthomas.com/2018/01/new-year-new-monospace/</guid>
      <pubDate>Wed, 03 Jan 2018 00:00:00 GMT</pubDate>
      
      <description>&lt;p&gt;If you’ve spent any amount of time speaking with me about coding, you’ve probably heard me enthuse about typefaces. Much like mattresses are the unsung heroes of a full third of our lives, coding fonts are rarely discussed, but constantly stared at.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>If you’ve spent any amount of time speaking with me about coding, you’ve probably heard me enthuse about typefaces. Much like mattresses are the unsung heroes of a full third of our lives, coding fonts are rarely discussed, but constantly stared at.</p><span id="more"></span><p>In the tradition of trying out new things for the new year, I want to share a few of my favorite coding typefaces. If you’ve been staring at the same letterforms for a while, maybe consider a change!</p><h2 id="SF-Mono"><a href="#SF-Mono" class="headerlink" title="SF Mono"></a>SF Mono</h2><p><img src="/2018/01/new-year-new-monospace/0-SFMono.png" alt="SF Mono"></p><p>A relative newcomer, SF Mono is Apple’s monospace variant for its fantastic <a href="https://developer.apple.com/fonts/">San Francisco family</a>. It comes in six weights (useful if you use multiple sizes at once) and features some of the same personality its proportional cousins bring to macOS. If you own a Sierra-or-thereafter Mac, you already have it, though it <a href="https://simonfredsted.com/1438">takes some steps to install</a>.</p><h2 id="Fira-Mono-Fira-Code"><a href="#Fira-Mono-Fira-Code" class="headerlink" title="Fira Mono&#x2F;Fira Code"></a>Fira Mono&#x2F;Fira Code</h2><p><img src="/2018/01/new-year-new-monospace/1-FiraCode.png" alt="Fira Code"></p><p>I’m a huge fan of the <a href="https://mozilla.github.io/Fira/">Fira family</a> (as of this writing, this blog uses Fira exclusively), and its <a href="https://fonts.google.com/specimen/Fira+Mono">monospaced version</a> is no exception. The slightly whimsical serifs don’t detract from the business of programming, and it’s surprisingly readable at any size. The <a href="https://github.com/tonsky/FiraCode">alternate “Code” version</a> adds programming-specific ligatures, if that’s your thing.</p><h2 id="PT-Mono"><a href="#PT-Mono" class="headerlink" title="PT Mono"></a>PT Mono</h2><p><img src="/2018/01/new-year-new-monospace/2-PTMono.png" alt="PT Mono"></p><p>The <a href="https://fonts.google.com/specimen/PT+Sans">PT family</a> traces its origins to Russian typefaces, and you can still detect the hint of Cyrillic letterforms in its <a href="https://fonts.google.com/specimen/PT+Mono">monospaced</a> form. It’s limited to two weights, so beware if you find yourself shifting between display pixel densities.</p><h2 id="Verily-Serif-Mono"><a href="#Verily-Serif-Mono" class="headerlink" title="Verily Serif Mono"></a>Verily Serif Mono</h2><p><img src="/2018/01/new-year-new-monospace/3-VerilySerifMono.png" alt="Verily Serif Mono"></p><p>If a traditional, literary typeface is more your style, give <a href="https://www.fontsquirrel.com/fonts/verily-serif-mono">Verily</a> a try. Its refined serifs seem plucked from your favorite hardcover, though I find it grows quickly distracting on-screen.</p><h2 id="Fantasque-Sans-Mono"><a href="#Fantasque-Sans-Mono" class="headerlink" title="Fantasque Sans Mono"></a>Fantasque Sans Mono</h2><p><img src="/2018/01/new-year-new-monospace/4-FantasqueSansMono.png" alt="Fantasque Sans Mono"></p><p>If you like your text editor on the playful side, <a href="https://fontlibrary.org/en/font/fantasque-sans-mono">Fantasque</a> is for you. For a typeface described as “the mutant child of Comic Sans and Helvetica Neue”, Fantasque looks quite good on languages from JavaScript to HTML.</p><h2 id="As-For-Me…"><a href="#As-For-Me…" class="headerlink" title="As For Me…"></a>As For Me…</h2><p>I’m going to give Adobe’s excellent <a href="https://adobe-fonts.github.io/source-code-pro/">Source Code Pro</a> a few weeks on my editor’s surface. It’s a lovely standby that always helps me clear my head. After that, who knows? <a href="https://www.dafont.com/monofur.font">I might just go nuts</a>:</p><p><img src="/2018/01/new-year-new-monospace/5-monofur.png" alt="monofur"></p><p>What about you? Have I missed your favorite? Have a visceral reaction to any of these? Weigh in below, and happy coding!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2018/01/new-year-new-monospace/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>A More Reactive Build Tool</title>
      <link>http://timgthomas.com/2015/10/a-more-reactive-build-tool/</link>
      <guid>http://timgthomas.com/2015/10/a-more-reactive-build-tool/</guid>
      <pubDate>Wed, 28 Oct 2015 00:00:00 GMT</pubDate>
      
      <description>&lt;p&gt;An interesting philosophy I’ve been introduced to while building apps with &lt;a href=&quot;https://facebook.github.io/react/&quot;&gt;React&lt;/a&gt; is that of avoiding static config files. Even HTML, arguably one of the most venerable “config” languages out there, has been replaced with a superset that can contain JavaScript, &lt;a href=&quot;https://facebook.github.io/jsx/&quot;&gt;React’s JSX&lt;/a&gt;. Newer trends even recommend &lt;a href=&quot;https://speakerdeck.com/vjeux/react-css-in-js&quot;&gt;supplementing &lt;em&gt;CSS&lt;/em&gt; with JavaScript&lt;/a&gt;, so you can make changes to styles based on application state in near real-time.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>An interesting philosophy I’ve been introduced to while building apps with <a href="https://facebook.github.io/react/">React</a> is that of avoiding static config files. Even HTML, arguably one of the most venerable “config” languages out there, has been replaced with a superset that can contain JavaScript, <a href="https://facebook.github.io/jsx/">React’s JSX</a>. Newer trends even recommend <a href="https://speakerdeck.com/vjeux/react-css-in-js">supplementing <em>CSS</em> with JavaScript</a>, so you can make changes to styles based on application state in near real-time.</p><span id="more"></span><p>One of the “complementary tools” to React (and the one recommended by many example apps I’ve encountered) is <a href="http://webpack.github.io/">Webpack</a>: a self-described “module bundler” that’s also commonly used to compile and process images, CSS, and other soon-to-be-static assets. Though Webpack is often suggested, I encountered several problems that led me to look elsewhere for setting up a build task. In this post, we’ll look at a few of those problems and what I ended up replacing Webpack with to solve them.</p><p><strong>TL;DR:</strong> If you want to jump straight to the good parts, I’ve created an <a href="https://github.com/TimGThomas/building-react-with-broccoli">example app hosted on GitHub</a> that covers everything in this post.</p><h2 id="A-Web-pack-of-Trouble"><a href="#A-Web-pack-of-Trouble" class="headerlink" title="A (Web)pack of Trouble"></a>A (Web)pack of Trouble</h2><p>When I was first getting started with React, I found the guides to be lacking with regards to setting up and maintaining a local development environment. Admittedly, I’m very spoiled by the <a href="http://emberjs.com/">Ember</a> ecosystem and <a href="http://www.ember-cli.com/">Ember CLI</a>, but I eventually happened on “<a href="https://blog.risingstack.com/the-react-way-getting-started-tutorial/">The React.js Way</a>” blog series, which advocates using Webpack for this purpose. I started using it, but quickly ran into a number of issues:</p><p><strong>Regular expressions.</strong> Web pack uses “<a href="http://webpack.github.io/docs/using-loaders.html">loaders</a>” to transform files, which rely on regular expressions to select the files to be transformed. Coming from the world of <a href="http://gruntjs.com/">Grunt</a> and friends, which uses very readable strings like <code>src/**/*.js</code> to represent files, expressions like <code>/src\/.+.js$/</code> make my head hurt, and I’m utterly unable to create new expressions without <a href="http://www.regular-expressions.info/">a reference guide</a>.</p><p><strong>Magic strings.</strong> Once you’ve managed to select your files using arcane RegEx strings, you’ll need to tell Webpack how to transform them. Webpack implicitly imports these loaders, then relies on string parsing to figure out what to do to the files, and in what order. Here’s an example <a href="http://webpack.github.io/docs/using-loaders.html#loaders-in-require">from the Webpack documentation</a>:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">require</span>(<span class="string">&quot;!style!css!less!bootstrap/less/bootstrap.less&quot;</span>)</span><br></pre></td></tr></table></figure><p>Aside from <a href="https://vimeo.com/97318798">using Bootstrap</a>, there are more insidious issues with this approach: one, it’s very unclear what, exactly, each of these processing steps does (and from which package they’re loaded), and, two, it turns out they’re executed from right to left, thereby guaranteeing I’ll get the execution order backwards <em>every time</em> I write a config file. Even after you decipher this processing instruction, you still need to import your CSS into your JavaScript, of course. <a href="https://github.com/webpack/css-loader#usage">Wait: <em>what</em>?</a></p><p><strong>Confusing documentation.</strong> Your mileage may vary, but I had a heck of a time deciphering the <a href="http://webpack.github.io/docs/">official Webpack documentation</a>. I mostly relied on other confused individuals who had divined the secrets of Webpack’s functionality and <a href="http://www.christianalfoni.com/articles/2015_04_19_The-ultimate-webpack-setup">blogged about it</a>.</p><p>I normally try to stick with new concepts for a while when learning a new language&#x2F;library&#x2F;framework; after all, these ideas and tools typically exist for a reason, and it can sometimes take a while to really grok them. With Webpack, though, I kept running into the same issues, with nothing but hacky-feeling workarounds to “solve” them. So, instead, I went back to the drawing board to look for an alternative.</p><h2 id="Eat-Your-Vegetables"><a href="#Eat-Your-Vegetables" class="headerlink" title="Eat Your Vegetables"></a>Eat Your Vegetables</h2><p>If you’ve spent any length of time talking shop with me, you’ve probably heard me mention <a href="https://github.com/broccolijs/broccoli">Broccoli</a>. If you haven’t, here’s the gist: <a href="https://speakerdeck.com/timgthomas/chocolate-covered-vegetables-tasty-workflows-with-broccoli">I’m a huge fan</a>. I find it insanely simple to start with, yet solidly scalable when the need arises. Massive build systems have been built from it (read more about the aforementioned Ember CLI if you’re interested), yet even at that level of complexity, it’s pretty straightforward to work with.</p><p>When I finally made the decision to ditch Webpack, I first thought of Broccoli, even though I honestly wasn’t sure if it would solve all of my issues. I wanted, in no particular order, something that would:</p><ul><li>Let me use React and libraries written for it (most of which used calls to <code>require()</code>, meaning I couldn’t just stick more <code>&lt;script&gt;</code> tags on a page);</li><li>Compile any non-standard JavaScript, including JSX for templating and ES2015 for, mostly, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">arrow functions</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings">template strings</a>;</li><li>Process any CSS I might need (without making me import it into JavaScript files, naturally); and</li><li>Run all of this stuff in a web server.</li></ul><p>As it happens, Broccoli’s pretty amazing at all of these, even with the JSX compilation (the cause for most of my uncertainty). Let’s see how to set up a simple React app with it.</p><h2 id="Replacing-Webpack-with-Broccoli"><a href="#Replacing-Webpack-with-Broccoli" class="headerlink" title="Replacing Webpack with Broccoli"></a>Replacing Webpack with Broccoli</h2><p>Taking the requirements from the previous section, here’s what we want Broccoli to do:</p><ol><li>Compile any JSX and&#x2F;or ES2015 in our JavaScript files.</li><li>Bundle the scripts together, respecting any dependencies using <code>require()</code>.</li><li>Process our CSS from, say, <a href="http://sass-lang.com/">Sass</a>.</li><li>Serve everything from a web server.</li></ol><p>To start with, let’s install Broccoli. It’s an <a href="https://www.npmjs.com/">npm</a> package, so you’ll probably want to run <a href="https://docs.npmjs.com/cli/init"><code>npm init</code></a> and get yourself a <code>package.json</code> file you can save these dependencies to first. After that, install Broccoli:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ npm install -g broccoli-cli</span><br><span class="line">$ npm install --save-dev broccoli</span><br></pre></td></tr></table></figure><p>The first command installs the Broccoli binary, while the second tells our app that it’ll need Broccoli as a dependency. Next, let’s make a simple Broccoli build file, named <code>Brocfile.js</code>. This file is a <a href="https://nodejs.org/api/modules.html#modules_modules">node module</a>, so we’ll be using calls to <code>require()</code> to bring in dependencies, and expose any outputs with <code>module.exports</code>.</p><p>Broccoli works primarily with directory paths, called “<a href="https://github.com/broccolijs/broccoli#plugin-api-specification">trees</a>”, that represent files and folders in your app. If we wanted Broccoli to act as a passthrough and not do any real processing, all we’d need in <code>Brocfile.js</code>—assuming our app assets are in an <code>app</code> folder—is:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="string">&#x27;app&#x27;</span>;</span><br></pre></td></tr></table></figure><p>We need a bit more than this, so let’s continue. First, we’ll need to install React, since our code depends on it. You’ll use a similar method if you want to install other packages on which your runtime code depends. Install it with the following npm command:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ npm install --save react</span><br></pre></td></tr></table></figure><p>Next, we’ll use two Broccoli helper packages to accomplish Objectives #1 and #2 (compiling and bundling our JavaScript), so run these commands to install them. Note that we’re installing these with <code>--save-dev</code>, not just <code>--save</code>, since they’re used for <em>building</em>, and not <em>running</em>, this app.</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ npm install --save-dev broccoli-babel-transpiler</span><br><span class="line">$ npm install --save-dev broccoli-browserify</span><br></pre></td></tr></table></figure><p><code>broccoli-babel-transpiler</code> is a Broccoli wrapper around the excellent <a href="https://babeljs.io/">Babel library</a>. When we use it, the package will convert any ES2015 code we might right into code that runs in the majority of modern browsers (<a href="https://babeljs.io/docs/faq/">TL;DR: IE9+</a>). As it happens, Babel also features support for <a href="https://babeljs.io/docs/usage/jsx/">converting JSX templates into JavaScript</a>, as well, so that problem solves itself! We’ll then use <a href="http://browserify.org/">Browserify</a> to take care of those <code>require()</code> calls. Here’s what our Brocfile looks like now, after we’ve imported and used these two packages:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> browserify = <span class="built_in">require</span>(<span class="string">&#x27;broccoli-browserify&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> babel = <span class="built_in">require</span>(<span class="string">&#x27;broccoli-babel-transpiler&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> js = <span class="string">&#x27;app&#x27;</span>;</span><br><span class="line">js = <span class="title function_">babel</span>(js, &#123;&#125;);</span><br><span class="line">js = <span class="title function_">browserify</span>(js, &#123;</span><br><span class="line">  <span class="attr">entries</span>: [ <span class="string">&#x27;./app.js&#x27;</span> ],</span><br><span class="line">  <span class="attr">outputFile</span>: <span class="string">&#x27;app.js&#x27;</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="string">&#x27;app&#x27;</span>;</span><br></pre></td></tr></table></figure><p>Broccoli lets us pass trees (like <code>app</code> in the above example) through varying processing steps, which will be executed in order (and, if you ask me, with far less confusion than Webpack’s approach).</p><p>Let’s move on to Objective #3: processing CSS. There are a number of CSS preprocessors, and a number of Broccoli plugins for them, but let’s go with one of my favorites, Sass. Install the <a href="https://github.com/joliss/broccoli-sass"><code>broccoli-sass</code></a> package with <code>npm install --save-dev broccoli-sass</code>, and point it at your CSS directory in <code>Brocfile.js</code>:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> compileSass = <span class="built_in">require</span>(<span class="string">&#x27;broccoli-sass&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> css = <span class="title function_">compileSass</span>([ <span class="string">&#x27;app/styles&#x27;</span> ], <span class="string">&#x27;app.scss&#x27;</span>, <span class="string">&#x27;app.css&#x27;</span>);</span><br></pre></td></tr></table></figure><p>I’ll leave the explanation of this plugin to the <code>broccoli-sass</code> documentation, but, in essence, we grab the uncompiled Sass code from <code>app/styles</code> and transform it, starting with <code>app.scss</code>.</p><p>At this point, we’ve run into a bit of a problem. With <code>module.exports</code>, we can only export a single tree object, but what we want is to “merge” the compiled JavaScript from Objectives #1 and #2 with the compiled CSS from Objective #3. Another Broccoli plugin to the rescue: <a href="https://github.com/joliss/broccoli-merge-trees"><code>broccoli-merge-trees</code></a>. This package, hopefully unsurprisingly, can merge our two (or more!) trees together. Here’s an example where we also bring in a <code>public</code> directory:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> merge = <span class="built_in">require</span>(<span class="string">&#x27;broccoli-merge-trees&#x27;</span>);</span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="title function_">merge</span>([ <span class="string">&#x27;public&#x27;</span>, js, css ]);</span><br></pre></td></tr></table></figure><p>Let’s then create an <code>index.html</code> file that will represent the starting point of our app. We’ll stick this file in the <code>public</code> directory since it doesn’t require any special processing or compilation. You may notice that the build steps we’ve created output two files: <code>app.js</code> and <code>app.css</code>. We’ll want to reference these in this HTML file like so:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="meta">&lt;!doctype <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;utf-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">link</span> <span class="attr">href</span>=<span class="string">&quot;app.css&quot;</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>(Your App)<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;app.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>What about Objective #4? You’ll be pleased to know Broccoli comes with a simple web server preinstalled! To start it, run:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ broccoli serve</span><br></pre></td></tr></table></figure><p>Then visit <code>http://localhost:4200/</code> in your favorite web browser (I don’t know where the port number comes from, but I like to think it’s inspired by the late <a href="https://en.wikipedia.org/wiki/Douglas_Adams">Douglas Adams</a>). If all goes well, you should see your React app in all its compiled and bundled glory!</p><hr><p>If you’ve been fighting with Webpack for building your React apps—or if you, too, struggle with setting up a React dev environment—why not give Broccoli a try? Alternatively, if you’re a die-hard Webpacker, or if you’ve found another build tool to solve Webpack’s issues, I’d love to hear what’s keeping your React apps built!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2015/10/a-more-reactive-build-tool/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>The Making of “You Might Not Need JavaScript”</title>
      <link>http://timgthomas.com/2015/09/the-making-of-stateful-css/</link>
      <guid>http://timgthomas.com/2015/09/the-making-of-stateful-css/</guid>
      <pubDate>Thu, 10 Sep 2015 00:00:00 GMT</pubDate>
      
      <description>&lt;p&gt;Last week, I had the pleasure of presenting at the &lt;a href=&quot;http://www.meetup.com/javascript-austin/&quot;&gt;JavaScript Austin&lt;/a&gt; meetup. For this month’s meetup, I gave my “stateful CSS” talk (titled “Form with Function” or “&lt;a href=&quot;http://www.meetup.com/javascript-austin/events/225015546/&quot;&gt;You Might Not Need JavaScript&lt;/a&gt;“, depending on how trolling I feel at the time). If you haven’t seen it yet, there’s a video of it &lt;a href=&quot;https://vimeo.com/131410261&quot;&gt;on Vimeo&lt;/a&gt;:&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>Last week, I had the pleasure of presenting at the <a href="http://www.meetup.com/javascript-austin/">JavaScript Austin</a> meetup. For this month’s meetup, I gave my “stateful CSS” talk (titled “Form with Function” or “<a href="http://www.meetup.com/javascript-austin/events/225015546/">You Might Not Need JavaScript</a>“, depending on how trolling I feel at the time). If you haven’t seen it yet, there’s a video of it <a href="https://vimeo.com/131410261">on Vimeo</a>:</p><span id="more"></span><iframe src="https://player.vimeo.com/video/131410261?title=0&amp;color=35aba5" width="500" height="281" frameborder="0" webkitAllowFullScreen="webkitAllowFullScreen" mozallowfullscreen="mozallowfullscreen" allowFullScreen="allowFullScreen"> </iframe><p>There’s a bit of a plot twist at the end of the talk that I get a lot of questions about (watch the video above first if you don’t want spoilers). In this post, we’ll look at how this plot twist was created.</p><h2 id="Spoiler-Alert"><a href="#Spoiler-Alert" class="headerlink" title="Spoiler Alert"></a>Spoiler Alert</h2><p>If you’re reading this, I assume you’ve either watched the above video, or you don’t care about spoilers (you monster). Okay, here’s the big plot twist:</p><blockquote><p>My entire presentation—the slides, the inline CSS editing, everything—was built without a single line of JavaScript.</p></blockquote><p>Let’s take a look at how to pull that off.</p><h2 id="Thinking-without-JavaScript"><a href="#Thinking-without-JavaScript" class="headerlink" title="Thinking without JavaScript"></a>Thinking without JavaScript</h2><p>A slide deck doesn’t have many “features” beyond showing one slide at a time (and having some way to switch between those). As it happens, we have access to an HTML element that <em>also</em> shows one thing at a time: a radio button.</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;slide&quot;</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span> <span class="attr">checked</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> &gt;</span><span class="comment">&lt;!-- Slide 1 --&gt;</span><span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;slide&quot;</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> &gt;</span><span class="comment">&lt;!-- Slide 2 --&gt;</span><span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;slide&quot;</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> &gt;</span><span class="comment">&lt;!-- Slide 3 --&gt;</span><span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Now, if we could somehow link the “checked” state of a radio button to the visibility of another element, we’d have the beginnings of a slide deck right there. Select the radio buttons in the following <a href="http://codepen.io/TimGThomas/pen/LppWpY/">pen</a> to see what happens:</p><p data-height="250" data-theme-id="1840" data-slug-hash="LppWpY" data-default-tab="result" data-user="TimGThomas" class="codepen" style="height:250px">See the Pen <a href='http://codepen.io/TimGThomas/pen/LppWpY/'>LppWpY</a> by Tim G. Thomas (<a href='https://codepen.io/TimGThomas'>@TimGThomas</a>) on <a href='http://codepen.io'>CodePen</a>.</p><script async src="//assets.codepen.io/assets/embed/ei.js"></script><p>So far, we’ve got a passable—albeit boring—slide deck, and all it took was some very basic HTML and a little clever CSS. Turns out styling elements is pretty straightforward thanks to the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/%3Achecked"><code>:checked</code></a> pseudo-class and the <code>+</code> (<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_selectors">adjacent</a>) selector:</p><figure class="highlight css"><table><tr><td class="code"><pre><span class="line"><span class="comment">/* Hide all slides by default. */</span></span><br><span class="line"><span class="selector-class">.slide</span> &#123;</span><br><span class="line">  <span class="attribute">display</span>: none;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* But show the currently-selected one. */</span></span><br><span class="line"><span class="selector-tag">input</span><span class="selector-attr">[name=<span class="string">&#x27;slide&#x27;</span>]</span><span class="selector-pseudo">:checked</span> + <span class="selector-class">.slide</span> &#123;</span><br><span class="line">  <span class="attribute">display</span>: block;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="radioButton-hide()" style="text-transform:initial">radioButton.hide()</h2><p>You’re more than welcome to stop here, as what we’ve covered so far is <em>technically</em> all you need to make your own JavaScript-less styles, but there’s more we can do.</p><p>Seeing all of those radio buttons sucks, so let’s get rid of them:</p><figure class="highlight css"><table><tr><td class="code"><pre><span class="line"><span class="selector-tag">input</span><span class="selector-attr">[name=<span class="string">&#x27;slide&#x27;</span>]</span> &#123;</span><br><span class="line">  <span class="attribute">display</span>: none;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>That’s better, but now we have no way of moving through the slides. Fortunately, this is already (partially) solved for us: browsers will let you switch between radio button values with your keyboard. Try it out below: click on a radio button, then use your arrow keys to select different options. Obviously, this won’t work if you’re on a device without a keyboard, so keep that in mind if your slides’ consumers will be on their phones:</p><p data-height="150" data-theme-id="1840" data-slug-hash="xwwqRK" data-default-tab="result" data-user="TimGThomas" class="codepen" style="height:150px">See the Pen <a href='http://codepen.io/TimGThomas/pen/xwwqRK/'>xwwqRK</a> by Tim G. Thomas (<a href='https://codepen.io/TimGThomas'>@TimGThomas</a>) on <a href='http://codepen.io'>CodePen</a>.</p><script async src="//assets.codepen.io/assets/embed/ei.js"></script><p>Next, we’ll have to link each slide to its radio button. If we’re hiding the inputs, we need some way of giving them focus so that the browser can work its keyboard magic. This is as easy as either giving each input an ID and changing each slide to be a <code>&lt;label&gt;</code>…</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">id</span>=<span class="string">&quot;slide_1&quot;</span> <span class="attr">name</span>=<span class="string">&quot;slide&quot;</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">&quot;slide_1&quot;</span>&gt;</span><span class="comment">&lt;!-- ... --&gt;</span><span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br></pre></td></tr></table></figure><p>…or wrapping each combination in its own <code>&lt;label&gt;</code>:</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">label</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span> <span class="attr">name</span>=<span class="string">&quot;slide&quot;</span> <span class="attr">type</span>=<span class="string">&quot;radio&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span>&gt;</span><span class="comment">&lt;!-- ... --&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">label</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Either technique will make each slide “clickable” to set the focus on the radio buttons, thus enabling keyboard movement.</p><p>Give each slide some CSS that makes it look like a real slide deck, and you’re good!</p><h2 id="Inline-CSS-Editing"><a href="#Inline-CSS-Editing" class="headerlink" title="Inline CSS Editing"></a>Inline CSS Editing</h2><p>My slide deck also included the ability to edit CSS on the fly and see it instantly update. This is actually a very old <a href="https://css-tricks.com/show-and-edit-style-element/">CSS Trick</a> that works well to this day. Just move your <code>&lt;style&gt;</code> block inside your <code>&lt;body&gt;</code>, set its style to <code>display: block</code>, and give it the <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_Editable"><code>contenteditable</code></a> attribute: browsers will use it for styling and <em>you</em> can use it for CSS demos. The CSS Tricks site has a great <a href="https://css-tricks.com/examples/ShowCSS/">demo page</a> for playing around with this feature.</p><hr><p>That’s all there is to it! A few lines of HTML per slide, a sprinkling of CSS, and a little <code>&lt;style&gt;</code> block trickery, and you’ve got yourself a modern—and JavaScript free!— slide deck! If you’d like to learn more about (mis-)using CSS for behavior, <a href="https://www.google.com/search?q=fun+with+stateful+css+site:timgthomas.com">read my blog series on “stateful CSS”</a>, <a href="https://vimeo.com/131410261">watch the presentation video</a>, and check out the <a href="https://github.com/TimGThomas/stateful-css-slides/">code for my slides on GitHub</a>.</p><p>If you’ve seen or built any great functionality with little or no CSS, share in the comments!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2015/09/the-making-of-stateful-css/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Deploying Ember CLI Apps to Parse Cloud Code</title>
      <link>http://timgthomas.com/2015/09/Deploying-Ember-CLI-Apps-to-Parse-Cloud-Code/</link>
      <guid>http://timgthomas.com/2015/09/Deploying-Ember-CLI-Apps-to-Parse-Cloud-Code/</guid>
      <pubDate>Wed, 02 Sep 2015 00:00:00 GMT</pubDate>
      
      <description>&lt;p&gt;I’m a big fan of &lt;a href=&quot;https://parse.com/&quot;&gt;Parse&lt;/a&gt;: their backend-as-a-service works great for the type of apps I build, which generally have little to no “server” and communicate primarily through REST endpoints.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>I’m a big fan of <a href="https://parse.com/">Parse</a>: their backend-as-a-service works great for the type of apps I build, which generally have little to no “server” and communicate primarily through REST endpoints.</p><span id="more"></span><p>Just the other day, I discovered that their back-end can <a href="http://blog.parse.com/announcements/goodbye-web-servers-hello-parse-hosting/">host static files</a>, meaning I could move my deployed <a href="http://emberjs.com/">Ember</a> apps away from services like <a href="http://aws.amazon.com/s3/">S3</a> or <a href="https://www.heroku.com/">Heroku</a>, thus simplifying (and cheapening) my deployments. Getting an <a href="http://www.ember-cli.com/">Ember CLI</a> app to run on Parse was a little less than frictionless, though, and, in this post, we’ll look at how to manage it.</p><p>To get started, you’ll need:</p><ul><li><a href="https://www.parse.com/signup">A Parse account</a> (there’s a free option) and <a href="https://parse.com/account/keys">Account Key</a>,</li><li><a href="https://parse.com/apps">A Parse application</a>, and</li><li>An Ember CLI app.</li></ul><h2 id="But-First-a-Caveat"><a href="#But-First-a-Caveat" class="headerlink" title="But First, a Caveat"></a>But First, a Caveat</h2><p>To be fair, deploying static files to Parse (such as those generated by Ember CLI) is quite simple. The Parse team provides a <a href="https://parse.com/docs/js/guide#command-line">command line tool</a> to deploy your code and assets, and it works well. What makes deploying Ember apps tricky has to do with <a href="http://guides.emberjs.com/v2.0.0/routing/specifying-the-location-api/">Ember’s URLs</a>.</p><p>By default, Ember CLI apps use a browser’s history API, which gives you URLs like <code>your-app.com/photos/1</code>. Here’s the issue: if a user navigates directly to that URL, most web servers will look for either static files or a defined route to serve, neither of which we’ll have after deploying this app.</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ curl -s -w <span class="string">&quot;%&#123;http_code&#125;&quot;</span> http://your-app.com/photos/1 -o /dev/null</span><br><span class="line">&gt; 404 <span class="comment"># Ruh roh.</span></span><br></pre></td></tr></table></figure><p>To fix this, we can tell Ember CLI to use “hash”-based URLs instead (like <code>your-app.com/#/photos/1</code>), which we’ll see how to do momentarily. This tells the server to load the root document, and Ember can then step in to figure out what route you’re looking at based on what’s past the “hash” symbol.</p><p>Now that’s out of the way, let’s get started deploying our Ember CLI app to Parse.</p><h2 id="The-Easy-Way"><a href="#The-Easy-Way" class="headerlink" title="The Easy Way"></a>The Easy Way</h2><p><strong>Update Ember CLI’s location type.</strong> We now know that history-based URLs will break when Parse serves the app from static files, so let’s change our app to use hashes instead: in <code>config/environment.js</code>, simply change the <code>locationType</code> property from <code>&#39;auto&#39;</code> to <code>&#39;hash&#39;</code>.</p><p><strong>Get your project Parse-ready.</strong> The fastest way to do this is to create a new Parse app using their command line tool. From there, you can either copy the files you need into an existing project, or create a new Ember CLI project inline. Using the Parse CLI, run <code>parse generate</code> and answer its questions. You’ll see a few files in there that you’ll need in your Ember app:</p><ul><li>The <code>/cloud</code> folder contains any custom server code your Parse app needs. The Parse CLI generates some default code in <code>main.js</code>…you can take it or leave it, but you’ll need the <code>cloud</code> directory either way.</li><li>The <code>/public</code> folder is where your compiled Ember app will belong. You don’t need to copy this over; we’ll make our own.</li><li><code>.parse.local</code> contains some properties that tell Parse to which app this code will belong. <em><strong>Warning:</strong> since this file contains your application’s unique key, make sure you don’t check it in to public source control. The <a href="https://github.com/fivetanley/ember-cli-dotenv"><code>ember-cli-dotenv</code></a> library can help with this.</em></li><li><code>.parse.project</code> tells Parse what version of its SDK to use. This one’s safe to stick on GitHub. :)</li></ul><p>For more details, check out the <a href="(https://parse.com/apps/quickstart#cloud_code/unix">Parse documentation on the subject</a>.</p><p><strong>Deploy!</strong> This step requires a bit more prep. What we need is to compile the Ember app into a <code>public</code> directory, then copy the Parse files from the previous step, then tell the Parse CLI to perform the deploy. I use a bash script for this, but be warned: I’m not a bash expert by any means, so feedback is definitely appreciated.</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Compile the Ember app.</span></span><br><span class="line">ember build -prod -o dist/public</span><br><span class="line"></span><br><span class="line"><span class="comment"># Copy Parse files and any Cloud Code.</span></span><br><span class="line"><span class="built_in">cp</span> .parse.project dist/.parse.project</span><br><span class="line"><span class="built_in">cp</span> .parse.local dist/.parse.local</span><br><span class="line"><span class="built_in">cp</span> -R cloud dist/cloud</span><br><span class="line"></span><br><span class="line"><span class="comment"># Deploy to Parse.</span></span><br><span class="line"><span class="built_in">cd</span> dist</span><br><span class="line">parse deploy</span><br><span class="line"></span><br><span class="line"><span class="comment"># Clean up after we finish.</span></span><br><span class="line"><span class="built_in">cd</span> ..</span><br><span class="line"><span class="built_in">rm</span> -rf dist</span><br></pre></td></tr></table></figure><p>Just run the bash script with <code>sh your-file-name.sh</code>, or maybe set it as an <a href="https://docs.npmjs.com/cli/run-script">npm package script</a>.</p><h2 id="The-Hard-er-Way"><a href="#The-Hard-er-Way" class="headerlink" title="The Hard(-er) Way"></a>The Hard(-er) Way</h2><p>At this point, you should have a fully-operational Ember app running on Parse…but we can do better. Let’s change our deploy process so we can use those history-based URLs.</p><p><strong>Reset things.</strong> To start, change your app’s <code>locationType</code> parameter (in <code>config/environment.js</code>) back to <code>&#39;auto&#39;</code>. No use in sticking with hash-based URLs anymore!</p><p><strong>Make a mini node app.</strong> We’ll need to tell Parse to always serve up the root document (located at <code>public/index.html</code>) to any and all requests so that Ember can take over routing. Fortunately, this is easily accomplished by giving Parse a <a href="http://blog.parse.com/announcements/building-parse-web-apps-with-the-express-web-framework/">simple node app</a> that it will run alongside serving static files. The following code is from <a href="https://twitter.com/erikch">Erik Hanchett</a>‘s great blog post on <a href="http://www.programwitherik.com/setup-your-ember-project-with-node/">serving Ember apps from Express</a>:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> app = <span class="title function_">express</span>();</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;*&#x27;</span>, <span class="keyword">function</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">  <span class="comment">// <span class="doctag">TODO:</span> Send the contents of &quot;public/index.html&quot;.</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>();</span><br></pre></td></tr></table></figure><p>Parse starts by looking for files in the <code>public</code> directory before it will run this simple server, so we won’t need to worry about not handling routes for static assets like CSS and JavaScript. From the <a href="https://parse.com/docs/js/guide#hosting-static-content">Parse documentation</a>:</p><blockquote><p>When a request goes to a URL of your subdomain, Parse will first look for a matching file in the <code>public</code> directory. If there is no match, then Parse will invoke any Express request handlers that you have registered in Cloud Code.</p></blockquote><p>To <a href="https://parse.com/docs/js/guide#hosting-creating-a-web-app">tell Parse about this node server</a>, have your app’s <code>main.js</code> file import it with <code>require(&#39;cloud/app.js&#39;);</code> on the first line.</p><p><strong>Send down the root file.</strong> Unfortunately, Parse’s node implementation lacks certain features (like Express’s <a href="http://expressjs.com/api.html#res"><code>Response</code></a> object’s <code>sendFile()</code> function) that would make sending down a static file trivial. Instead, I’m using a bit of a hack: in the deploy script, make the root file an EJS template, then tell the node app to render it (something the Parse node binary <a href="https://parse.com/docs/js/guide#hosting-rendering-templates"><em>can</em> do</a>):</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> app = <span class="title function_">express</span>();</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">set</span>(<span class="string">&#x27;views&#x27;</span>, <span class="string">&#x27;cloud/views&#x27;</span>);</span><br><span class="line">app.<span class="title function_">set</span>(<span class="string">&#x27;view engine&#x27;</span>, <span class="string">&#x27;ejs&#x27;</span>);</span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">bodyParser</span>());</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;*&#x27;</span>, <span class="keyword">function</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">  res.<span class="title function_">render</span>(<span class="string">&#x27;index&#x27;</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>();</span><br></pre></td></tr></table></figure><p>Here’s the new part of the bash script that does that:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Create the &#x27;views&#x27; directory.</span></span><br><span class="line"><span class="built_in">mkdir</span> -p dist/cloud/views</span><br><span class="line"></span><br><span class="line"><span class="comment"># Copy the root file.</span></span><br><span class="line"><span class="built_in">cp</span> dist/public/index.html dist/cloud/views/index.html</span><br><span class="line"></span><br><span class="line"><span class="comment"># Rename it to &#x27;*.ejs&#x27;</span></span><br><span class="line"><span class="built_in">mv</span> dist/cloud/views/index.html dist/cloud/views/index.ejs</span><br></pre></td></tr></table></figure><p><strong>Deploy! Again!</strong> With the build script modified, we’re ready to deploy again! This time, our script will also copy the <code>index.html</code> file into the <code>cloud/views</code> folder so our mini-node app can serve it. All that’s left is to visit your Parse app and see if everything works correctly. If not…well, Parse has some great <a href="https://parse.com/docs/js/guide#command-line-reading-the-logs">logging tools</a>!</p><hr><p>Even with the workaround for Ember’s history-based URLs, I’m thrilled with how easy it is to deploy an Ember CLI app to Parse. If you’re already a Parse user, or have been looking for an excuse to give it a try, why not try your hand at deploying an Ember app? If you run into any issues, or have suggestions for ways to streamline this process, share them in the comments!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2015/09/Deploying-Ember-CLI-Apps-to-Parse-Cloud-Code/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Installing Ember CLI on Windows</title>
      <link>http://timgthomas.com/2015/07/installing-ember-cli-on-windows/</link>
      <guid>http://timgthomas.com/2015/07/installing-ember-cli-on-windows/</guid>
      <pubDate>Mon, 20 Jul 2015 00:00:00 GMT</pubDate>
      
      <description>&lt;p&gt;Yesterday, I made a huge mistake: I decided to install &lt;a href=&quot;http://www.ember-cli.com/&quot;&gt;Ember CLI&lt;/a&gt; on a brand-new Windows installation. Over &lt;em&gt;two hours&lt;/em&gt; later, I was finally able to build and run an Ember CLI project. I’d like to share some of that process with you, and perhaps save you some of the headaches I encountered.&lt;/p&gt;</description>
      
      
      
      <content:encoded><![CDATA[<p>Yesterday, I made a huge mistake: I decided to install <a href="http://www.ember-cli.com/">Ember CLI</a> on a brand-new Windows installation. Over <em>two hours</em> later, I was finally able to build and run an Ember CLI project. I’d like to share some of that process with you, and perhaps save you some of the headaches I encountered.</p><span id="more"></span><h2 id="Installing-Ember-CLI"><a href="#Installing-Ember-CLI" class="headerlink" title="Installing Ember CLI"></a>Installing Ember CLI</h2><p>Before I begin, some bad news: when I began this arduous journey, I didn’t realize how difficult it would become, so I neglected to document most of the error messages I received. If I’m feeling masochistic and ever try this again, I’ll update this post with more detailed errors.</p><p>Also, I based this post on my experiences, so your mileage may vary (and I certainly hope it does). For reference, I’m using Windows 7 Ultimate, 64-bit. Let’s get started:</p><ol><li><strong>npm.</strong> On Windows, nested packages in <code>node_modules</code> often <a href="https://github.com/joyent/node/issues/6960">overflow Windows’s file path length limitations</a>. To bypass this restriction, the npm 3 (beta) <a href="http://www.infoq.com/news/2015/06/npm">stores modules in a flat structure</a>. I didn’t install this at first, and soon ran into issues. To get npm 3, install <a href="https://nodejs.org/">Node</a>, then use the <a href="https://github.com/felixrieseberg/npm-windows-upgrade"><code>npm-windows-upgrade</code></a> package to upgrade it. One caveat: the package’s README <em>implies</em> you should <a href="https://github.com/felixrieseberg/npm-windows-upgrade#usage">run the upgrade in an Administrator console</a>, but this later caused several permissions errors. Everything worked as expected when I ran the command in a non-Admin window.</li><li><strong>Python.</strong> One of Ember CLI’s dependencies, <code>node-gyp</code>, requires <a href="https://www.python.org/">Python</a>. If you’re unfamiliar with the Python ecosystem, there are two major, and <a href="https://wiki.python.org/moin/Python2orPython3">somewhat-incompatible</a>, versions. The package doesn’t state which version it needs, but it will complain if you’ve installed the wrong one. You’ll want some flavor of 2.x (I used the newest as of this writing, <a href="https://www.python.org/downloads/">2.7.10</a>).</li><li><strong>Visual Studio.</strong> Yep, you read that right: you need <em>Visual Freaking Studio</em> to build Ember apps on Windows. <code>node-gyp</code> only <a href="https://github.com/TooTallNate/node-gyp#installation">requires some of VS’s C++ compilers</a>, but a full install is the reliable way to get those. A free version is available (I used the recommended “<a href="https://www.visualstudio.com/en-us/products/visual-studio-express-vs.aspx">Visual Studio 2013 Express for Windows Desktop</a>”), but set aside at least an hour to find, download, and install it. Oh, and say “goodbye” to a clean “Programs and Features” screen after you’re done:<br><img src="/2015/07/installing-ember-cli-on-windows/programs-and-features.png" alt="Installing Visual Studio adds a few apps"></li><li><strong>Bower.</strong> You’ll also need <a href="http://bower.io/">Bower</a> for browser-side package management, but this was a painless installation for me. Just <code>npm install bower -g</code> and you should be good to go.</li></ol><h2 id="Building-an-Ember-CLI-Project"><a href="#Building-an-Ember-CLI-Project" class="headerlink" title="Building an Ember CLI Project"></a>Building an Ember CLI Project</h2><p>At this point, I was about 90 minutes into the process…but I wasn’t done yet. After installing Ember CLI, you’ll need to install a project’s npm and Bower dependencies (with <code>npm install</code> and <code>bower install</code>, respectively). The Bower packages installed fine, but npm’s were another story:</p><ol><li><strong>Folder permissions.</strong> I encountered several npm <code>EACCES</code> errors when installing a project’s dependencies, stating that I didn’t have permissions for <code>C:\Program Files\nodejs</code>. This is an <a href="http://stackoverflow.com/questions/16151018/npm-throws-error-without-sudo">easy fix</a> on OSes that have <code>chown</code>, but I had to use Windows’s infamous “Security” UI instead. Though my user account is a member of the “Administrators” group, which has access to that folder, that’s not enough: I needed to give my user account full access to the <code>nodejs</code> folder and its children. The permissions errors disappeared after that.</li><li><strong>Disconnections.</strong> Once the permissions errors cleared up, I started receiving <code>ECONNRESET</code> errors a few seconds into downloading npm packages. Re-running <code>npm install</code> sometimes worked, but <a href="http://stackoverflow.com/questions/18419144/npm-not-working-read-econnreset">changing the npm registry to a non-HTTPS version</a> solved the issue.</li></ol><p>Finally, two hours after I began, I was able to build and run an Ember CLI app. Unfortunately, I then discovered Windows is abysmally slow at <em>compiling</em> the Ember CLI stuff. There’s <a href="https://github.com/felixrieseberg/ember-cli-windows">an npm package to help</a>, but it was still pretty painful for me after that…but at least it was working.</p><p>I’m still trying to remember exactly <em>why</em> I embarked on this near-Sisyphean experience—I had a MacBook Pro within arm’s reach on which I develop most of my Ember apps—but I hope documenting my painful journey will help yours be less so. Happy Embering!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2015/07/installing-ember-cli-on-windows/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>NDC Oslo 2015</title>
      <link>http://timgthomas.com/2015/06/ndc-oslo-2015/</link>
      <guid>http://timgthomas.com/2015/06/ndc-oslo-2015/</guid>
      <pubDate>Mon, 29 Jun 2015 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;Earlier this month I had the pleasure of returning to Oslo, Norway, for another fantastic &lt;a href=&quot;http://www.ndcoslo.com/&quot;&gt;Norwegian Dev</description>
        
      
      
      
      <content:encoded><![CDATA[<p>Earlier this month I had the pleasure of returning to Oslo, Norway, for another fantastic <a href="http://www.ndcoslo.com/">Norwegian Developers Conference</a>. As usual, the conference featured amazing speakers providing invaluable content, and I’m honored to have been asked to join them for a third year.</p><p>This year, I gave a talk on adding interactions to your web apps using only CSS, a topic on which I’ve frequently blogged in the past. A full recording of my talk is <a href="https://vimeo.com/131410261">on Vimeo</a>, and embedded below. The talk’s slides—written entirely with HTML and CSS—<a href="http://timgthomas.github.io/stateful-css-slides/">can be viewed online</a> and are <a href="https://github.com/TimGThomas/stateful-css-slides">on GitHub</a>, as well.</p><iframe src="https://player.vimeo.com/video/131410261?title=0&amp;color=35aba5" width="500" height="281" frameborder="0" webkitAllowFullScreen="webkitAllowFullScreen" mozallowfullscreen="mozallowfullscreen" allowFullScreen="allowFullScreen"> </iframe><blockquote><p>As the web becomes a more vivid, interactive medium, page payloads increase dramatically. Images, templates, and behavioral plugins add needed richness, but also code complexity and, yes, file size. Fortunately, there’s an unusual way to add some great interactions to your web apps without bloating your pages: with CSS!</p></blockquote><p>If you’d like to learn more about this topic, check out my blog posts on the subject:</p><ul><li><a href="/2012/05/mute-your-asynchronous-uis-with-stateful-css/">Mute Your Asynchronous UIs with Stateful CSS</a></li><li><a href="/2013/10/fun-with-stateful-css-a-view-edit-screen/">Fun with Stateful CSS: A View&#x2F;Edit Screen</a></li><li><a href="/2013/10/fun-with-stateful-css-modals/">Fun with Stateful CSS: Modals</a></li><li><a href="/2013/10/fun-with-stateful-css-tabs/">Fun with Stateful CSS: Tabs</a></li></ul><p>As always, I’d love to hear your feedback. Have some comments or suggestions? Let me know in the comments!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2015/06/ndc-oslo-2015/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Simple File Tricks with Atom</title>
      <link>http://timgthomas.com/2015/04/simple-file-tricks-with-atom/</link>
      <guid>http://timgthomas.com/2015/04/simple-file-tricks-with-atom/</guid>
      <pubDate>Tue, 28 Apr 2015 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;I’m a huge fan of &lt;a href=&quot;https://atom.io/&quot;&gt;Atom&lt;/a&gt;, &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;’s &lt;a href=&quot;https://github.com/atom/atom&quot;&gt;</description>
        
      
      
      
      <content:encoded><![CDATA[<p>I’m a huge fan of <a href="https://atom.io/">Atom</a>, <a href="https://github.com/">GitHub</a>’s <a href="https://github.com/atom/atom">open source</a> text editor. The more time I can spend in it (instead of switching contexts between different applications), the better. In this post, I’d like to share with you a few simple file operations you can perform inside Atom instead of ⌘+Tab-ing elsewhere:</p><h2 id="Moving-Files"><a href="#Moving-Files" class="headerlink" title="Moving Files"></a>Moving Files</h2><p>You may have used Atom’s “rename” feature a time or two, but did you know you can also use it to move files, as well? When you open the “rename” palette, Atom displays the file’s full path (relative to the project root). Want to relocate the file? Simply change the path and hit return:</p><p><img src="/2015/04/simple-file-tricks-with-atom/moving-files.gif" alt="Using Atom to move a file"></p><h2 id="Copying-Pasting-Files"><a href="#Copying-Pasting-Files" class="headerlink" title="Copying&#x2F;Pasting Files"></a>Copying&#x2F;Pasting Files</h2><p>The next time you need to copy and paste a file, why not use Atom instead of your OS’s file explorer? Right-click a file, select “Duplicate”, and Atom prompts you for the file’s new name. Much like moving a file, just change the path to wherever you’d like to copy the new file, hit return, and presto!</p><h2 id="Creating-New-Files"><a href="#Creating-New-Files" class="headerlink" title="Creating New Files"></a>Creating New Files</h2><p>Sure, new files are only a couple of mouse clicks away, but why should you even have to take your hands off your keyboard? Spoiler alert: you don’t have to! Atom includes a command to do just that, but it’s not bound to a keyboard shortcut…yet. Here’s how to make that happen:</p><ol><li>Open your Atom keymap (Mac: “Atom” &gt; “Open Your Keymap”; Windows: “File” &gt; “Open Your Keymap”).</li><li>Add the following text, replacing the keystroke with one of your preference (I took mine from a <a href="https://github.com/skuroda/Sublime-AdvancedNewFile">Sublime plugin</a>):<figure class="highlight cson"><table><tr><td class="code"><pre><span class="line"><span class="string">&#x27;body&#x27;</span>:</span><br><span class="line">  <span class="string">&#x27;cmd-alt-n&#x27;</span>: <span class="string">&#x27;tree-view:add-file&#x27;</span></span><br></pre></td></tr></table></figure></li><li>Save your keymap file.</li></ol><p>Now, just hit ⌥⌘N (or whatever you specified your shortcut to be) and Atom presents you with the “new file” palette. Enter a path for the new file (again, relative to the project root) and hit return&#x2F;enter. Your shiny new file will present itself instantly.</p><p>Have you used Atom’s features to do things otherwise thought the domain of other apps? Share them in the comments!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2015/04/simple-file-tricks-with-atom/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Tame Your Illustrator Layers with Isolation Mode</title>
      <link>http://timgthomas.com/2015/03/tame-your-illustrator-layers-with-isolation-mode/</link>
      <guid>http://timgthomas.com/2015/03/tame-your-illustrator-layers-with-isolation-mode/</guid>
      <pubDate>Tue, 10 Mar 2015 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;When designing UIs, I make copious use of &lt;a href=&quot;http://www.adobe.com/products/illustrator.html&quot;&gt;Illustrator’s&lt;/a&gt; layers. I love the f</description>
        
      
      
      
      <content:encoded><![CDATA[<p>When designing UIs, I make copious use of <a href="http://www.adobe.com/products/illustrator.html">Illustrator’s</a> layers. I love the flexibility of designing parts of an interface separately, then toggling them on and off to see how various parts fit together.</p><p>Having dozens of layers is great when you’re putting the finishing touches on a design or figuring out what pieces fit best together, but it can be a pain sorting through everything in the <a href="https://helpx.adobe.com/illustrator/using/layers.html#layers_panel_overview">Layers panel</a> until then. Keeping a mental note of where all your objects and groups are located—not to mention navigating the sea of <a href="http://www.urbandictionary.com/define.php?term=norgie">norgies</a>—can be a nightmare. Fortunately, Illustrator has the perfect feature that can help.</p><h2 id="Introducing-Isolation-Mode"><a href="#Introducing-Isolation-Mode" class="headerlink" title="Introducing Isolation Mode"></a>Introducing Isolation Mode</h2><p>You may be familiar with Isolation Mode if you use <a href="https://helpx.adobe.com/illustrator/using/symbols.html">symbols</a> in Illustrator: double-clicking a placed symbol enters a mode where changes you make apply only to the symbol, and not the rest of the document. In fact, the Layers panel only shows the symbol’s objects, so there’s no chance you’ll accidentally select some external object.</p><p>Fortunately, you can also enter Isolation Mode on other things (including layers, groups, and even single <em>objects</em>), as well! To start, select a layer in the Layers panel (you just need to select the layer, not “target” it), then click the panel’s “menu” icon and choose “Enter Isolation Mode”.</p><p><img src="/2015/03/tame-your-illustrator-layers-with-isolation-mode/enter-isolation-mode.gif" alt="The Layers panel&#39;s context menu"></p><h2 id="Working-in-Isolation"><a href="#Working-in-Isolation" class="headerlink" title="Working in Isolation"></a>Working in Isolation</h2><p>After entering Isolation Mode, you’ll notice a couple of changes to the Illustrator UI. First, the Layers Panel updates to only show the layer you’re working with. Second, everything <em>not</em> in the isolated layer will fade out, allowing you to visually focus on the layer you’ve selected. Finally, a new bar appears below the active tab (or below its rulers, if you have those enabled) that shows the hierarchy of this layer:</p><p><img src="/2015/03/tame-your-illustrator-layers-with-isolation-mode/isolation-mode-bar.gif" alt="The Isolation Mode bar"></p><p>Now that you’re in Isolation Mode, any new objects you create will become part of the isolated layer, and you won’t be able to select anything outside that layer (that part alone is my favorite part of this feature).</p><p>To leave Isolation Mode, you have a couple of options. If you’re in a deeply-nested layer, you can click the name of an ancestor layer in the Isolation Mode bar to switch to Isolation Mode for that layer. Alternatively, just double-click an empty part of the document window to exit Isolation Mode entirely.</p><p>I hope you find Illustrator’s Isolation Mode feature as invaluable as I do when working with complex documents. Have any layer productivity tips of your own? Share them in the comments!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2015/03/tame-your-illustrator-layers-with-isolation-mode/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Prairie Dev Con 2015</title>
      <link>http://timgthomas.com/2015/03/prairie-dev-con-2015/</link>
      <guid>http://timgthomas.com/2015/03/prairie-dev-con-2015/</guid>
      <pubDate>Wed, 04 Mar 2015 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;Earlier this week, I had the extreme pleasure to return to Winnipeg, Manitoba, to speak at the 2015 edition of the &lt;a href=&quot;http://prairi</description>
        
      
      
      
      <content:encoded><![CDATA[<p>Earlier this week, I had the extreme pleasure to return to Winnipeg, Manitoba, to speak at the 2015 edition of the <a href="http://prairiedevcon.com/">Prairie Dev Con</a> (the conference’s ninth annual event).</p><p>I gave two talks at the event: first, an introduction to the <a href="http://broccolijs.com/">Broccoli</a> build tool, entitled “Chocolate-Covered Vegetables”. We discussed how to use the build tool and some <a href="http://broccoliplugins.com/">essential plugins</a> to get the most of it. Slides for the talk are <a href="https://speakerdeck.com/timgthomas/chocolate-covered-vegetables-tasty-workflows-with-broccoli">available on SpeakerDeck</a>:</p><p><a href="https://speakerdeck.com/timgthomas/chocolate-covered-vegetables-tasty-workflows-with-broccoli"><img src="/2015/03/prairie-dev-con-2015/chocolate-covered-vegetables.png" alt="Slides"></a></p><p>On the second day, I presented on “Stateful CSS”: a way of adding behavior to web apps with no JavaScript. We discussed building <a href="http://codepen.io/TimGThomas/pen/qijKp">tabs</a>, <a href="http://codepen.io/TimGThomas/pen/KILyq">modals</a>, and <a href="http://codepen.io/TimGThomas/pen/PwBYaZ">more</a>, all with only CSS. The slides (themselves created using only CSS!) are <a href="https://github.com/TimGThomas/stateful-css-slides">available on GitHub</a>, and the code examples can be found in a <a href="http://codepen.io/collection/AWvrMk/">CodePen collection</a>.</p><p>PrDC is absolutely one of my favorite conferences, and I encourage you to check it out if you ever find yourself in the area in early spring. The organizer, <a href="http://geekswithblogs.net/dlussier/Default.aspx">D’Arcy Lussier</a>, knows how to put together a <em>seriously</em> epic conference. If you have any feedback about my talks or their content, let me know in the comments!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2015/03/prairie-dev-con-2015/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Controllerless Actions in Ember.js</title>
      <link>http://timgthomas.com/2015/02/Controllerless-Actions-in-Ember-js/</link>
      <guid>http://timgthomas.com/2015/02/Controllerless-Actions-in-Ember-js/</guid>
      <pubDate>Tue, 17 Feb 2015 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;Ember.js includes a robust eventing system for sending &lt;a href=&quot;http://emberjs.com/guides/templates/actions/&quot;&gt;actions&lt;/a&gt; from user-facin</description>
        
      
      
      
      <content:encoded><![CDATA[<p>Ember.js includes a robust eventing system for sending <a href="http://emberjs.com/guides/templates/actions/">actions</a> from user-facing components deeper into your application (often into a <a href="http://emberjs.com/guides/controllers/">Controller</a>):</p><figure class="highlight handlebars"><table><tr><td class="code"><pre><span class="line"><span class="template-tag">&#123;&#123;#<span class="name"><span class="built_in">each</span></span> post in posts&#125;&#125;</span><span class="language-xml"></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;<span class="name">a</span> </span></span><span class="template-variable">&#123;&#123;<span class="name"><span class="built_in">action</span></span> <span class="string">&#x27;markAsRead&#x27;</span> post&#125;&#125;</span><span class="language-xml"><span class="tag">&gt;</span>Mark as Read<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"></span><span class="template-tag">&#123;&#123;/<span class="name"><span class="built_in">each</span></span>&#125;&#125;</span></span><br></pre></td></tr></table></figure><p>While Controllers are the perfect place for logic used on a single view, you may find that, over time, that behavior becomes duplicated in multiple places. Creating <a href="http://emberjs.com/api/classes/Ember.Mixin.html">Mixins</a> is one way of <a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>-ing up your code (and is the preferred solution for interaction logic), but, in this post, we’ll look at another method that’s more <a href="http://en.wikipedia.org/wiki/Business_logic">domain logic</a>–friendly.</p><p>To begin with, let’s take a look at a simple Controller that contains both interaction and domain logic:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Ember</span>.<span class="property">Controller</span>.<span class="title function_">extend</span>(&#123;</span><br><span class="line">  <span class="attr">actions</span>: &#123;</span><br><span class="line">    <span class="attr">readMoreLess</span>: <span class="keyword">function</span>(<span class="params">post</span>) &#123;</span><br><span class="line">      post.<span class="title function_">set</span>(<span class="string">&#x27;expanded&#x27;</span>, !post.<span class="title function_">get</span>(<span class="string">&#x27;expanded&#x27;</span>));</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">markAsRead</span>: <span class="keyword">function</span>(<span class="params">post</span>) &#123;</span><br><span class="line">      post.<span class="title function_">set</span>(<span class="string">&#x27;read&#x27;</span>, <span class="literal">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>Expanding and collapsing a blog post’s content is clearly an interaction concern (in other words, not something you’ll likely want to persist to a database), but marking a post as “read” is probably something more meaningful to your application. If we move this functionality to a <a href="http://emberjs.com/guides/models/">Model</a> object, our action handler may end up looking something like this:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">Ember</span>.<span class="property">Controller</span>.<span class="title function_">extend</span>(&#123;</span><br><span class="line">  <span class="attr">actions</span>: &#123;</span><br><span class="line">    <span class="attr">readMoreLess</span>: <span class="keyword">function</span>(<span class="params">post</span>) &#123; <span class="comment">/* ... */</span> &#125;,</span><br><span class="line">    <span class="attr">markAsRead</span>: <span class="keyword">function</span>(<span class="params">post</span>) &#123;</span><br><span class="line">      post.<span class="title function_">markAsRead</span>();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>At this point, there’s not much use for having an action on our Controller that does nothing but delegate out to the Model for this behavior. Fortunately, we can hook into Handlebars for a solution:</p><figure class="highlight handlebars"><table><tr><td class="code"><pre><span class="line"><span class="template-tag">&#123;&#123;#<span class="name"><span class="built_in">each</span></span> post in posts&#125;&#125;</span><span class="language-xml"></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;<span class="name">a</span> </span></span><span class="template-variable">&#123;&#123;<span class="name"><span class="built_in">action</span></span> <span class="string">&#x27;markAsRead&#x27;</span> <span class="attr">target</span>=post&#125;&#125;</span><span class="language-xml"><span class="tag">&gt;</span>Mark as Read<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"></span><span class="template-tag">&#123;&#123;/<span class="name"><span class="built_in">each</span></span>&#125;&#125;</span></span><br></pre></td></tr></table></figure><p>By telling Handlebars what the <a href="http://emberjs.com/guides/templates/actions/#toc_specifying-a-target">target of this action</a> should be (in this case, the post object itself), we can bypass an explicit action handler on a Controller entirely (and it’s entirely possible you may be able to completely remove a Controller in some cases) and call a function directly on that Model. Note, however, that the function names must match <em>exactly</em> between your templates and your model objects (much like a Controller’s action’s name must match the template):</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">BlogPost</span>.<span class="title function_">reopen</span>(&#123;</span><br><span class="line">  <span class="attr">markAsRead</span>: <span class="keyword">function</span>(<span class="params"></span>) &#123; <span class="comment">/* ... */</span> &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>This approach won’t work in all cases, and you’ll want to keep an eye on your behavior to make sure you’re only including domain logic in Model objects (remember: interaction logic duplication should be kept in check with Mixins), but hopefully you’ll find your Controllers are cleaner and more expressive as a result.</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2015/02/Controllerless-Actions-in-Ember-js/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Quick and Easy Icon Fonts</title>
      <link>http://timgthomas.com/2015/02/quick-and-easy-icon-fonts/</link>
      <guid>http://timgthomas.com/2015/02/quick-and-easy-icon-fonts/</guid>
      <pubDate>Thu, 05 Feb 2015 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;Creating icon fonts is one of my favorite things to do these days. With all the great browser design and development tools available, I’m</description>
        
      
      
      
      <content:encoded><![CDATA[<p>Creating icon fonts is one of my favorite things to do these days. With all the great browser design and development tools available, I’m using my pure design skills less and less; creating icons is one of the few times when I can sit down and do some solid vector-pushing.</p><p>If you’re unfamiliar with the concept, icon fonts are a way of symbols in your web apps without requiring images. They’re contained in a single typeface file (which means they only cost a single HTTP request), vector (so they’re infinitely scalable), and, since it’s still technically text, can be styled with CSS. A wide variety of icon fonts are available for use (many of them free), but some designs need a custom touch. In this post, you’ll see just how easy it is to make your own icons with some great tools.</p><h2 id="What-you’ll-need"><a href="#What-you’ll-need" class="headerlink" title="What you’ll need"></a>What you’ll need</h2><p>The only hard requirements you’ll need for this exercise are a) a vector graphics editor that can export to SVG (I’ll be using <a href="https://www.adobe.com/products/illustrator.html">Adobe Illustrator</a>) and b) and internet connection (one of the tools is online). Naturally, it helps to have some experience with the graphics editor you choose, but if you know how to draw lines and basic shapes, you’ll be just fine.</p><h2 id="Making-the-icons"><a href="#Making-the-icons" class="headerlink" title="Making the icons"></a>Making the icons</h2><p>To start, we’ll create a new document in Illustrator. Illustrator supports multiple <a href="https://helpx.adobe.com/illustrator/how-to/work-with-artboards.html">“artboards”</a> in one document, so we can make each one the exact size of our finished icons and keep them all in one file. For this example, we’ll use icons that are 16 pixels square, but you could choose any size that fits your design (though I generally stick to sizes in multiples of 8 pixels since they’re easier for me to design).</p><p><img src="/2015/02/quick-and-easy-icon-fonts/new-document.png" alt="Adobe Illustrator&#39;s &quot;New Document&quot; dialog"></p><p>Next, create the icon. Illustrator has a <a href="https://helpx.adobe.com/illustrator/using/drawing-pen-pencil-or-flare.html">myriad of tools</a> available for this, but I find myself using the Pen and Line Segment tools most often. The most important thing to keep in mind at this point is to stick to whole values for sizes and positions; putting a half-pixel-thick line in-between pixels is a one-way ticket to Blursville. In Illustrator, you can check the potential blurriness of an icon by turning on Pixel Preview (View &gt; Pixel Preview) and zooming in. I generally use a one-pixel grid while designing to make sure everything lines up <em>just so</em>, and check with Pixel Preview frequently.</p><p>For this example, we’ll create a simple “delete” icon. I used perpendicular lines to form an ‘x’, and made each one two pixels thick. Rounded caps may not add much visual interest for some screens, but if any of your users have high-density displays, they’ll appreciate the extra level of detail. (Note: in this image, I’ve reduced the opacity of the lines so you can see how the anchor points align perfectly with the pixel grid.)</p><p><img src="/2015/02/quick-and-easy-icon-fonts/construction-lines.png" alt="Our in-progress icon"></p><p>As I mentioned, I generally work with lines when making icons, but feel free to experiment with any of the vector tools at your disposal. Remember, though, that only <em>vector</em> shapes can be used for icon fonts, so any raster images (drop shadows are a common example) won’t come across in the final icon.</p><p>There’s one last thing we need to do before moving on: while lines are great to work with while constructing icons, icon fonts require filled shapes instead. To do this, “expand” the lines into shapes with the “Expand…” (Object &gt; Expand…) command. Next, I typically merge the two now-shapes together to make a single path with the <a href="https://helpx.adobe.com/illustrator/using/combining-objects.html">“Union” command</a> of the “Pathfinder” palette (Window &gt; Pathfinder).</p><p><img src="/2015/02/quick-and-easy-icon-fonts/line-construction.gif" alt="Line construction"></p><h2 id="Exporting-the-icons"><a href="#Exporting-the-icons" class="headerlink" title="Exporting the icons"></a>Exporting the icons</h2><p>Now that we’ve created our icon, we’re ready to export it to SVG. Illustrator makes this process incredibly easy, as you can save a document directly to that format. Here’s how:</p><ol><li>Choose File &gt; “Save a Copy…”. The “Save As…” command also works, but changes your open document to the saved copy, meaning you have to close it and re-open your original Illustrator file. “Save a Copy…” doesn’t do this.</li><li>From the “Format” selector, choose “SVG (svg)”, and click “Use Artboards” below it. If you so choose, you can also specify a certain range of artboards to export, but I typically export all of them at once so the output SVGs are never out of sync with my Illustrator file. If you have more than one or two icons in this file, you may want to save the SVGs in a separate folder: each artboard will become a separate file.</li><li>Next, you’ll select some options for the output SVG. I follow Adobe’s recommendations for the web from <a href="http://www.adobe.com/inspire/2013/09/exporting-svg-illustrator.html">“Exporting SVG for the web with Adobe Illustrator CC”</a>; scroll to the “Best export options for the web” section. When you click “OK”, your artboards will be turned into SVGs!</li><li>(Optional.) I find Illustrator does a passable job of exporting concise SVG markup, but, if you’d like to take another pass at it for some extra saved bytes, I recommend the <a href="https://github.com/svg/svgo-gui">SVGO</a> app. You could also edit out any extra line breaks and decimal places by hand if you’re so inclined.</li></ol><h2 id="Creating-the-icon-font"><a href="#Creating-the-icon-font" class="headerlink" title="Creating the icon font"></a>Creating the icon font</h2><p>At this point, you should have a number of SVGs that are all exactly 16 pixels square (or whatever your base size is) and nicely contained into their own files. There are a couple of options for you at this point: you could simply use the SVGs in your sites directly (SVG support in browsers is <a href="http://caniuse.com/#feat=svg">quite nice</a>, as it happens), but that’s a different post. Instead, we’re going to create an icon font out of our SVGs using the awesome IcoMoon app.</p><p>To get started, <a href="https://icomoon.io/app">fire up the IcoMoon app</a>. There are some great sets included with IcoMoon by default, but we’re creating our own, so feel free to ignore those.</p><p>Click “Import Icons” and navigate to your icon folder. Select any of the icons you’d like included in this font and click “Open”. If all goes well, you should instantly see your newly-crafted icons. If, instead, you see blank boxes, check that you converted your lines to shapes (in “Making the icons” above). By default, none of the icons we’ve uploaded are included in this icon font, so make sure the “select” tool (the first icon with the mouse cursor) is active, and click your uploaded icons. Each selected icon is outlined.</p><p><img src="/2015/02/quick-and-easy-icon-fonts/selected-icon.png" alt="A selected icon"></p><p>At this point, you <em>technically</em> already have an icon font. If you want, you can stop here, click “Generate Font” at the bottom of the app window, followed by “Download”, and use this font in your app; however, there are some optimizations we can perform at this point to make our lives as web designers easier.</p><p>First, I like to turn on “Quick Usage” (available in the “Generate Font” screen). This feature provides us with a <code>&lt;link&gt;</code> tag directly to this icon font, hosted by IcoMoon, that we can drop in to any web app and start using immediately. <a href="https://icomoon.io/#premium">Upgraded plans</a> feature permanently-available links, while the free version keeps them alive for 24 hours.</p><p>Next, I give names to each icon. IcoMoon uses the SVG file names to prepopulate names for each icon, so you’ll often end up with values like “iconcopy_delete”, which isn’t very clear (you’ll be forced to use this verbose name in your HTML, too). Just select the text and replace it with something better, like “delete”. IcoMoon updates your values automatically.</p><h2 id="Next-steps"><a href="#Next-steps" class="headerlink" title="Next steps"></a>Next steps</h2><p>At this point, you’re ready to start using this icon font! If you hover over one of the glyphs in IcoMoon’s “Generate Font” screen, you’ll see a “Get Code” link, which opens a modal describing exactly how to consume your newly-minted font. You can either use the <code>&lt;link&gt;</code> from Quick Usage, or download the font files and set it up yourself.</p><p>If you’d like to learn more about icon fonts, CSS Tricks has an <a href="http://css-tricks.com/examples/IconFont/">excellent article</a> on their use. If you’ve made your own icon font that you’d like to show off, or if you have any suggestions for improving this workflow, let me know in the comments!</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2015/02/quick-and-easy-icon-fonts/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Essential Animations for the Web</title>
      <link>http://timgthomas.com/2015/02/essential-animations-for-the-web/</link>
      <guid>http://timgthomas.com/2015/02/essential-animations-for-the-web/</guid>
      <pubDate>Tue, 03 Feb 2015 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;&lt;a href=&quot;http://rachelnabors.com/&quot;&gt;Rachel Nabors&lt;/a&gt; predicts 2015 will be “a year in motion for the web”, and it’s easy to see why: more</description>
        
      
      
      
      <content:encoded><![CDATA[<p><a href="http://rachelnabors.com/">Rachel Nabors</a> predicts 2015 will be “a year in motion for the web”, and it’s easy to see why: more and more sites are adding motion to communicate their designs, and the abundance of <a href="http://julian.com/research/velocity/">animation libraries</a> (not to mention progressively greater support for <a href="http://caniuse.com/#feat=css-transitions">CSS transitions</a>) makes it easier than ever to bring motion to your apps.</p><p>Like the rounded corner trend of old, however, it’s easy to jump on this particular bandwagon with reckless abandon, adding every conceivable animation without truly understanding <em>why</em>. In this post, we’ll look at a few common web animations, and how they support—rather than supplant—a design’s intent.</p><h2 id="The-Appear"><a href="#The-Appear" class="headerlink" title="The Appear"></a>The Appear</h2><p><img src="/2015/02/essential-animations-for-the-web/1-the-appear.gif" alt="An example of The Appear animation"></p><p>Admittedly, having an element simply <em>appear</em> on a page isn’t truly an “animation”, but I feel it’s important to list for two reasons: much like every app and site has a “design” even if it has no “designer”, instantly showing an element still qualifies as a transition between two states in your app, even if it’s not in motion <em>per se</em>. And, before the days of JavaScript libraries and CSS animations, it was the only “transition” available. Though The Appear may not stand as proudly as its more “motion-ey” cousins, it’s important to remember that we didn’t always have such refined tools at our disposal.</p><h2 id="The-Fade"><a href="#The-Fade" class="headerlink" title="The Fade"></a>The Fade</h2><p>One of the first animations I began using in my designs was the humble Fade. Simply adjusting the opacity of an element over time removes much of the jarring nature of The Appear, and adds an element of subtlety wherever it’s used.</p><p>Unfortunately, using The Fade sometimes requires rearranging elements on the page instantly <em>before</em> a new element can fade in, leading to similarly jarring results as The Appear.</p><p><img src="/2015/02/essential-animations-for-the-web/2-the-fade.gif" alt="An example of The Fade animation"></p><h2 id="The-Unfold"><a href="#The-Unfold" class="headerlink" title="The Unfold"></a>The Unfold</h2><p>The Unfold seems to follow The Fade quite closely in popularity, but, for me, it’s one of the first truly useful transitions I used. While The Fade uses opacity for its transition—an interaction rarely, if ever, seen in the physical realm—The Unfold relies purely on movement, and evokes a sense of opening a door or extracting a letter from an envelope. Revealing content in this way reinforces the sense that the newly-shown information was there all along, just waiting to be freed from its <code>overflow: hidden</code> prison.</p><p><img src="/2015/02/essential-animations-for-the-web/3-the-unfold.gif" alt="An example of The Unfold animation"></p><h2 id="The-Slide"><a href="#The-Slide" class="headerlink" title="The Slide"></a>The Slide</h2><p>While The Appear, The Fade, and The Unfold work well for <em>introducing</em> new content, you’ll sometimes need a way to animate the <em>removal</em> of something. The Slide is my go-to solution, as both provides visual interest and supports “removal” metaphor…in fact, it rather reminds me of sweeping papers off a messy desk.</p><p><img src="/2015/02/essential-animations-for-the-web/4-the-slide.gif" alt="An example of The Slide animation"></p><p>An inelegant follow-up to The Slide is to instantly—and jarringly—delete the space the recently-removed element once occupied, but pair The Slide with The Fold (The Unfold’s helpful cousin), and your users will never be left wondering what happened to their nicely-stacked lists.</p><h2 id="The-Tint"><a href="#The-Tint" class="headerlink" title="The Tint"></a>The Tint</h2><p>Sometimes motion isn’t the best way of expressing change. Maybe a green element changes to red to indicate that a server is down, or a toggle switch changes from light to dark to signify it was just selected. In both cases, we’re not relying on movement to indicate change, but, rather, other appearance characteristics: I call this The Tint.</p><p><img src="/2015/02/essential-animations-for-the-web/5-the-tint.gif" alt="An example of The Tint animation"></p><p>This kind of inline change can be very impactful, especially when numerous items have their statuses updated in real-time, but can even help in very subtle ways, as with a button’s “hover” state.</p><p>Beware, however, that if your transitions are <em>too</em> subtle, many users may not notice them. Even seemingly-obvious changes (like a dramatic color shift) may be meaningless to users with difficulty seeing <a href="http://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html">small changes in contrast</a>.</p><h2 id="Runners-Up"><a href="#Runners-Up" class="headerlink" title="Runners-Up"></a>Runners-Up</h2><p>Two more animations that have gained a great deal of popularity recently are The Flip and The Shake. Though I’m unsure of the exact origin of either of these transitions, I remember first seeing them in native iOS apps.</p><p>I typically find The Flip hanging around <a href="http://semantic-ui.com/views/card.html">card-based UIs</a> (cards…card <em>flips</em>…makes sense) to hide less frequently–viewed details without having to  break the context of whatever content they were viewing. This animation can be very helpful (or, if you’re building an <a href="http://neonmob.com/">online trading card game</a>, downright <em>essential</em>), provided it’s obvious enough to people that certain elements can be interacted with in this way.</p><p><img src="/2015/02/essential-animations-for-the-web/6-the-flip.gif" alt="An example of The Flip animation"></p><p>Anyone who fat-fingers their OS X password is undoubtedly familiar with The Shake. One of the most deliciously-simple animations I’ve ever seen, The Shake is the perfect response to incorrectly input data. You needn’t move your eyes to see that something happened (yet it’s obvious something <em>did</em>), and the gesture so closely represents what many of us do when frustrated: give our phones, monitors, or produce a good jiggle.</p><p><img src="/2015/02/essential-animations-for-the-web/7-the-shake.gif" alt="An example of The Flip animation"></p><p>The next time you find yourself about to implement some carefully thought-out animation, think about the humble beginnings of what promises to be the Year in Motion for the Web. We’re just getting started bringing some amazing transitions to a historically-static medium, and the future looks more animated than ever before.</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2015/02/essential-animations-for-the-web/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Quick and Easy Filterable Lists in Ember.js</title>
      <link>http://timgthomas.com/2014/08/quick-and-easy-filterable-lists-in-ember-js/</link>
      <guid>http://timgthomas.com/2014/08/quick-and-easy-filterable-lists-in-ember-js/</guid>
      <pubDate>Thu, 07 Aug 2014 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;There are many great &lt;a href=&quot;http://demos.telerik.com/kendo-ui/grid/index&quot;&gt;filterable grids&lt;/a&gt; available for Javascript. Sometimes, tho</description>
        
      
      
      
      <content:encoded><![CDATA[<p>There are many great <a href="http://demos.telerik.com/kendo-ui/grid/index">filterable grids</a> available for Javascript. Sometimes, though, you just want an easy way to show a subset of items in a small list. In this post, we’ll look at doing just that in your <a href="http://emberjs.com/">Ember.js</a> applications.</p><p>Let’s start with a small list of books. In this fictional UI, we’ll show each book’s title and author, and let users filter the list of books by genre:</p><p><img src="/css/images/blog/2014-08-01-01.png" alt="A wireframe of what we&#39;re trying to do"></p><p>To begin, we need to polyfill a currently-missing component of Ember: radio buttons. It may seem odd, but these innocuous input fields are the key to this solution: we’ll bind the selected item’s value to an Ember property, which we’ll then use to filter the list. Matthew Anderson <a href="http://thoughts.z-dev.org/2013/07/04/post/">wrote a great post</a> on adding support for this input type, so we’ll start by adding the code from that post to the Ember app.</p><p>Next, let’s create a <a href="http://emberjs.com/guides/components/">Component</a> to house our filtering functionality. This step is optional, but helpful if you plan to filter multiple lists in your app, or if your code’s getting a bit messy.</p><figure class="highlight handlebars"><table><tr><td class="code"><pre><span class="line"><span class="template-variable">&#123;&#123;<span class="name">filterable-list</span> <span class="attr">list</span>=listToFilter&#125;&#125;</span></span><br></pre></td></tr></table></figure><p>In our Component, we’ll include a property, <code>filterBy</code>, to store the current filter (defaulted to “all”) from the selected radio button, as instructed by Mr. Anderson’s post. Our Component also needs a “proxy” list property (let’s call it <code>filteredList</code>). We’ll display this collection in the UI, and we can use its property function to perform the filtering. To start, this property will return the whole collection, but we’ll filter it shortly. Don’t forget that this property needs to respond to changes for both the list of objects itself as well as the selected filter:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">App</span>.<span class="property">FilterableListComponent</span> = <span class="title class_">Ember</span>.<span class="property">Component</span>.<span class="title function_">extend</span>(&#123;</span><br><span class="line">  <span class="attr">filterBy</span>: <span class="string">&#x27;all&#x27;</span>,</span><br><span class="line">  <span class="attr">filteredList</span>: <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">get</span>(<span class="string">&#x27;list&#x27;</span>);</span><br><span class="line">  &#125;.<span class="title function_">property</span>(<span class="string">&#x27;list&#x27;</span>, <span class="string">&#x27;filterBy&#x27;</span>)</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>Now let’s write the Handlebars template for this Component. We’ll need to use the new radio button View we added to the app earlier (one for each filter), and loop through the “proxy” list:</p><figure class="highlight handlebars"><table><tr><td class="code"><pre><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">ul</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;<span class="name">li</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    </span><span class="template-variable">&#123;&#123;<span class="name"><span class="built_in">view</span></span> Ember.RadioButton <span class="attr">name</span>=<span class="string">&#x27;filter&#x27;</span> <span class="attr">id</span>=<span class="string">&#x27;filter_all&#x27;</span></span></span><br><span class="line"><span class="template-variable">      <span class="attr">selectionBinding</span>=<span class="string">&#x27;filterBy&#x27;</span> <span class="attr">value</span>=<span class="string">&#x27;all&#x27;</span>&#125;&#125;</span><span class="language-xml"></span></span><br><span class="line"><span class="language-xml"></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">label</span> <span class="attr">for</span>=<span class="string">&quot;filter_all&quot;</span>&gt;</span>All<span class="tag">&lt;/<span class="name">label</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="comment">&lt;!-- other options omitted for brevity --&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">table</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;<span class="name">tr</span>&gt;</span><span class="comment">&lt;!-- column headers --&gt;</span><span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  </span><span class="template-tag">&#123;&#123;#<span class="name"><span class="built_in">each</span></span> filteredList&#125;&#125;</span><span class="language-xml"></span></span><br><span class="line"><span class="language-xml"></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">tr</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">td</span>&gt;</span></span><span class="template-variable">&#123;&#123;<span class="name">title</span>&#125;&#125;</span><span class="language-xml"><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">td</span>&gt;</span></span><span class="template-variable">&#123;&#123;<span class="name">author</span>&#125;&#125;</span><span class="language-xml"><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  </span><span class="template-tag">&#123;&#123;/<span class="name"><span class="built_in">each</span></span>&#125;&#125;</span><span class="language-xml"></span></span><br><span class="line"><span class="language-xml"></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">table</span>&gt;</span></span></span><br></pre></td></tr></table></figure><p>Finally, it’s time to hook up our filtering. We’ll use an object with properties that match those of the radio buttons, and values of functions that will perform the filtering. Then, when either the list of objects or the selected filter changes, we’ll perform the filtering by pulling the matching filter function from that object:</p><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">App</span>.<span class="property">FilterableListComponent</span> = <span class="title class_">Ember</span>.<span class="property">Component</span>.<span class="title function_">extend</span>(&#123;</span><br><span class="line">  <span class="attr">filterBy</span>: <span class="string">&#x27;all&#x27;</span>,</span><br><span class="line">  <span class="attr">filters</span>: &#123;</span><br><span class="line">    <span class="attr">all</span>: <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="comment">// Show all books.</span></span><br><span class="line">      <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">fantasy</span>: <span class="keyword">function</span>(<span class="params">book</span>) &#123;</span><br><span class="line">      <span class="comment">// Show only fantasy books.</span></span><br><span class="line">      <span class="keyword">return</span> book.<span class="title function_">get</span>(<span class="string">&#x27;genre&#x27;</span>) === <span class="string">&#x27;fantasy&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">filteredList</span>: <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="comment">// Get the filter from our `filters` object.</span></span><br><span class="line">    <span class="keyword">var</span> filterFunction = <span class="variable language_">this</span>.<span class="property">filters</span>[<span class="variable language_">this</span>.<span class="title function_">get</span>(<span class="string">&#x27;filterBy&#x27;</span>)];</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Perform the filtering with an array function.</span></span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">get</span>(<span class="string">&#x27;list&#x27;</span>).<span class="title function_">filter</span>(filterFunction);</span><br><span class="line">  &#125;.<span class="title function_">property</span>(<span class="string">&#x27;list&#x27;</span>, <span class="string">&#x27;filterBy&#x27;</span>)</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>Add in some nice styling, and we’ve got a pretty nice filterable list!</p><p data-height="268" data-theme-id="1840" data-slug-hash="cJwEp" data-default-tab="result" class='codepen'>See the Pen <a href='http://codepen.io/TimGThomas/pen/cJwEp/'>Filterable Lists in Ember.js</a> by Tim G. Thomas (<a href='http://codepen.io/TimGThomas'>@TimGThomas</a>) on <a href='http://codepen.io'>CodePen</a>.</p><script async src="//codepen.io/assets/embed/ei.js"></script>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2014/08/quick-and-easy-filterable-lists-in-ember-js/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Norwegian Usability</title>
      <link>http://timgthomas.com/2014/06/norwegian-usability/</link>
      <guid>http://timgthomas.com/2014/06/norwegian-usability/</guid>
      <pubDate>Thu, 12 Jun 2014 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;One of my favorite parts about traveling internationally is the ability to see how other cultures design everyday objects and experiences</description>
        
      
      
      
      <content:encoded><![CDATA[<p>One of my favorite parts about traveling internationally is the ability to see how other cultures design everyday objects and experiences. I had the opportunity to <a href="http://ndcoslo.com/">speak in Norway last week</a>, and took note of some of my favorite examples of usability:</p><h2 id="Hotel-Room-Keys"><a href="#Hotel-Room-Keys" class="headerlink" title="Hotel Room Keys"></a>Hotel Room Keys</h2><p>In the past year, I’ve had to request something like three or four additional room keys because I realized I hadn’t grabbed one…right after the room door slammed closed. What’s the solution? The locks in my Norwegian hotel wait for a full minute before engaging, giving you ample time to get to the elevator, remember you left your key, and rush back to the room. What’s more, you can turn the key card around and slide it into the lock to immediately bolt the door, ensuring you can only explicitly lock your room when you have your key card in hand.</p><p>In addition to the great at-the-door experience, the light switches just inside the room won’t even turn on unless a room key is inserted, providing both insurance that you don’t leave any lights on when you leave, and a convenient place to store your room key while you’re inside.</p><figure><img src="/css/images/blog/2014-06-10-00.jpg" alt="Light switches with a hotel room key card slot. Photo by @housecor." style="max-width:300px"><figcaption>Photo by <a href="https://twitter.com/housecor">@housecor</a>.</figcaption></figure><h2 id="Light-Switches"><a href="#Light-Switches" class="headerlink" title="Light Switches"></a>Light Switches</h2><p>Speaking of lights, most light switches I’ve encountered in the States fall into one of two categories. On one side of the spectrum is the style of a tiny, protruding block of plastic. It’s difficult to manipulate without physically pinching the plastic block with two fingers: a feat practically impossible when you’re carrying bags of groceries in both arms, for example.</p><p>The alternative is a much larger flattened toggle switch: a “rocker”. While it’s certainly much easier to switch in the aforementioned grocery scenario, I’ve frequently found them to be <em>too</em> sensitive, often turning lights on (or off) when I gently brush past. Their flat shape also makes it difficult to see the switch’s position from far away.</p><p>In Norway (and many other countries), however, light switches take on a more thoughtful appearance (see the above photo). The switches are square and generally larger in size, and feature a flat rocker switching mechanism that sticks out some distance from the wall at it’s farthest point. The result is a switch that’s easy to turn on and off (but not <em>too</em> easy) without requiring large amounts of dexterity, yet sizeable enough to be easily seen from across a room.</p><h2 id="Cigarette-Trash-Cans"><a href="#Cigarette-Trash-Cans" class="headerlink" title="Cigarette Trash Cans"></a>Cigarette Trash Cans</h2><p>I’m not a smoker, but it seems many Norwegians are: I encountered a seemingly large number of them in Oslo. What I <em>didn’t</em> encounter a large number of, however, were cigarette butts, and I credit two things with this: one, the Norwegians’ apparent desire to keep their country clean (shocking, I know), and two, these cleverly-obvious trash cans. The punctured recepticle opening practically <em>begs</em> to have a spent cigarette disposed of therein.</p><p><img src="/css/images/blog/2014-06-10-01.jpg" alt="A cigarette trash can in Oslo, Norway"></p><h2 id="Street-Signs"><a href="#Street-Signs" class="headerlink" title="Street Signs"></a>Street Signs</h2><p>The street sign system in the States is adequate, but that doesn’t mean it can’t be improved upon. One of the signs I remember having a problem with is the “do not enter” sign: the graphic itself makes sense, but the signs are often oriented so that you can’t easily see them unless you’re almost directly facing the street you’re forbidden to enter. I sometimes find myself leaning to one side while driving to make sure the sign I’m seeing is, in fact, of the “no entry” variety.</p><p>The Norwegian signs of the same purpose feature an ingenious solution: curved metal. From straight-on, the signs appear just as they would otherwise. From a cross street, however, you can still clearly see enough of the sign to realize you shouldn’t make that turn.</p><p><img src="/css/images/blog/2014-06-10-02.jpg" alt="A curved street sign in Oslo, Norway"></p><h2 id="Emergency-Exit-Signs"><a href="#Emergency-Exit-Signs" class="headerlink" title="Emergency Exit Signs"></a>Emergency Exit Signs</h2><p>I’ve been fortunate enough to never need the help of an emergency exit sign, but I always felt I’d be of two minds if I ever did need its navigational assistance: on one hand, I, as a person in hypothetical need of an emergency exit, would be quite pleased to see a convenient and well-labeled escape route. On the other hand, I’ve been trained from a young age that the color red means “stop” or “don’t do this”. Fortunately, the Norwegians (among many other countries, to be fair) have solved this problem entirely: make the exit sign green. The <a href="https://www.google.com/search?q=uk+emergency+exit&tbm=isch">Portal-esque iconography</a> is a nice touch.</p><h2 id="Shower-Faucets"><a href="#Shower-Faucets" class="headerlink" title="Shower Faucets"></a>Shower Faucets</h2><p>My least favorite morning ritual involves fiddling with the shower controls for fully half a minute trying to get the temperature <em>just right</em>. My hotel room featured the solution of my dreams: a shower that allowed you to specify the water’s temperature, in degrees, independent of the flow rate. When arriving at a suitably-equipped hotel—I had one in the UK last year, too—I just dial in the temperature before my first shower (a process that takes about three seconds) and never worry about it again.</p><p><img src="/css/images/blog/2014-06-10-03.jpg" alt="A shower faucet in Oslo, Norway"></p><h2 id="The-Oslo-Opera-House"><a href="#The-Oslo-Opera-House" class="headerlink" title="The Oslo Opera House"></a>The Oslo Opera House</h2><p>By far the most spectacular example of great usability I encountered on my trip, the Oslo Opera house is beautiful, iconic…and can be walked on. Almost the entire roof of the building is effectively a stone-floored plaza (that I’ve been told represents the Norwegians’ enthusiasm for mountain climbing), featuring breathtaking views of the city. What better example of usability than to turn something almost exclusively unusable for the public—a building’s roof—into something an entire city can enjoy?</p><p><img src="/css/images/blog/2014-06-10-04.jpg" alt="The Oslo Opera House in Norway"></p><p>Even though I interacted with (or sometimes just <em>looked at</em>) these items, experiences, and places only briefly during my trip to Oslo, I remember each one quite well: it’s amazing how some simple solutions to common problems can leave such a profound impact. What examples of great usability have you encountered on your travels?</p>]]></content:encoded>
      
      
      
      
      <comments>http://timgthomas.com/2014/06/norwegian-usability/#disqus_thread</comments>
      
    </item>
    
  </channel>
</rss>
