Shared posts

22 May 13:46

Fahrenheit 451 (2018)

by Dan Jones

I have trouble believing this could be better than the old film, but it certainly looks more intense.

01 Mar 03:32

Interaction

[They do not move.]
28 Feb 21:43

Star Wars Bedroom

Star Wars Bedroom

 

Now this is parenting done right! Dericrw posted this epic Star Wars themed kids bedroom complete with Millenium Falcon bed and a badass Nerf wall...

Star Wars Bedroom

Star Wars Bedroom

Star Wars Bedroom

Star Wars Bedroom

Star Wars Bedroom

Star Wars Bedroom

Star Wars Bedroom

Star Wars Bedroom

Star Wars Bedroom

Source: Dericrw

Follow us on:
 

February 28 2018
28 Feb 19:35

One Hour One Life

by Jason Kottke
Dan Jones

Looks interesting. It's open source, and available at https://github.com/jasonrohrer/OneLife/

Not good documentation on building it, though. I'm going to try to figure out how to build it and try it out.

Jason Rohrer, one of the most well-regarded indie video game makers out there (he made Passage, which is incredibly poignant for a video game that lasts only 5 minutes), has just released his latest game, One Hour One Life. Rohrer bills the game as “a multiplayer survival game of parenting and civilization building”. Here’s the trailer:

This game is about playing one small part in a much larger story. You only live an hour, but time and space in this game is infinite. You can only do so much in one lifetime, but the tech tree in this game will take hundreds of generations to fully explore. This game is also about family trees. Having a mother who takes care of you as a baby, and hopefully taking care of a baby yourself later in life. And your mother is another player. And your baby is another player. Building something to use in your lifetime, but inevitably realizing that, in the end, what you build is not for YOU, but for your children and all the countless others that will come after you. Proudly using your grandfather’s ax, and then passing it on to your own grandchild as the end of your life nears.

And looking at each life as a unique story. I was this kid born in this situation, but I eventually grew up. I built a bakery near the wheat fields. Over time, I watched my grandparents and parents grow old and die. I had some kids of my own along the way, but they are grown now… and look at my character now! She’s an old woman. What a life passed by in this little hour of mine. After I die, this life will be over and gone forever. I can be born again, but I can never live this unique story again. Everything’s changing. I’ll be born as a different person in a different place and different time, with another unique story to experience in the next hour…

That sounds kind of amazing, like a cross between Passage and something like Spore or Everything. And dare I say it’s a little Game Neverending-ish as well?

And check out the “thinking behind One Hour One Life” section at the bottom of the home page. It includes links to videos on the meaning of human life, Milton Friedman’s views on market capitalism (a riff on I, Pencil), and the Primitive Technology guy. (via andy)

Tags: Jason Rohrer   video   video games
28 Feb 18:43

Putting Your Phone in Grayscale Mode to Reduce the Urge to Use It

by John Gruber
Dan Jones

I tried this yesterday for most of the day. I found I had to turn it off when going home because having my maps in grayscale made it harder to scan it quickly.

Nellie Bowles, writing for The New York Times last month:

I’ve gone gray, and it’s great.

In an effort to break my smartphone addiction, I’ve joined a small group of people turning their phone screens to grayscale — cutting out the colors and going with a range of shades from white to black. First popularized by the tech ethicist Tristan Harris, the goal of sticking to shades of gray is to make the glittering screen a little less stimulating.

I’ve been gray for a couple days, and it’s remarkable how well it has eased my twitchy phone checking, suggesting that one way to break phone attachment may be to, essentially, make my phone a little worse. We’re simple animals, excited by bright colors, it turns out.

On the iPhone, you can manage this in the Display Accommodations section with General → Accessibility in Settings. The easiest way to use it is to enable “Color Filters” as the Triple-Click accessibility shortcut, all the way down at the very bottom of the Accessibility section. Then you can just triple-click the side button to toggle it.

I tried this while hanging out with some friends over Super Bowl weekend. They liked it more than I did. I can definitely see how this reduces the urge to turn to your phone the moment you’re bored, but to me it’s so unpalatable that I find it hard to use the phone. Your mileage may vary.

28 Feb 17:36

Self Care

by The Awkward Yeti

020218selfcare

28 Feb 17:36

All the Pop Culture Icons in the Same Universe

All the Pop Culture Icons in the Same Universe

 

Mind=Blown.

All the Pop Culture Icons in the Same Universe

Source: snuffels

Follow us on:
 

February 28 2018
28 Feb 12:42

Savage AF T-Shirt

by Erin Carstens

Do the kids who say "Savage AF" even know who Fred Savage is? Better question: do the adults who know who Fred Savage is also know why it's funny to see little Kevin Arnold's face on a T-shirt that says, "Savage AF .... *as Fred?" It's a pretty...

27 Feb 18:08

All the typefaces used on the iconic Huy Fong sriracha label

by Jason Kottke

Fonts in Use took a crack at identifying the crazy quilt of typefaces used on the label of Huy Fong sriracha.

Sriracha Fonts

The most prominent Latin text elements are rendered in a variety of informal script typefaces released by American Type Founders in the 20th century, namely Balloon and its shaded counterpart, Balloon Drop Shadow, as well as Brody. Smaller text on the back of the bottle is set in Impress and Tekton.

And they threw Arial in there for good measure. Oof. Don’t miss the first comment about the label’s Chinese fonts; “In the West, PMingLiu has become a prominent component of what some might call the “Asian diaspora aesthetics”. In East Asia, it is seen as the signature for those typographically unenlightened.”

P.S. No one knows who drew the label’s iconic rooster. And remember when people were stockpiling Huy Fong sriracha due to shortages? Simpler times.

Update: After I wondered on Twitter what the Huy Fong sriracha label would look like if the great Modernist designer Massimo Vignelli designed it, the folks at Major Interactive came up with this:

Sriracha Helvetica

*slow clap*

Tags: design   food   Massimo Vignelli   typography
27 Feb 16:29

Let’s Build a Custom Vue Router

by Hassan Djirdeh

Plenty of tutorials exist that do a great job in explaining how Vue’s official routing library, vue-router, can be integrated into an existing Vue application. vue-router does a fantastic job by providing us with the items needed to map an application’s components to different browser URL routes.

But, simple applications often don’t need a fully fledged routing library like vue-router. In this article, we'll build a simple custom client-side router with Vue. By doing so, we’ll gather an understanding of what needs to be handled to construct client-side routing as well as where potential shortcomings can exist.

Though this article assumes basic knowledge in Vue.js; we'll be explaining things thoroughly as we start to write code!

Routing

First and foremost: let’s define routing for those who may be new to the concept.

In web development, routing often refers to splitting an application’s UI based on rules derived from the browser URL. Imagine clicking a link and having the URL go from https://website.com to https://website.com/article/. That’s routing.

Routing is often categorized in two main buckets:

  • Server-side routing: the client (i.e. the browser) makes a request to the server on every URL change.
  • Client-side routing: the client only makes a request to the server upon initial-page load. Any changes to the application UI based on URL routes are then handled on the client.

Client-side routing is where the term single-page application (or SPA for short) comes in. SPAs are web apps that load only once and are dynamically updated with user interaction without the need to make subsequent requests to the server. With routing in SPAs, JavaScript is the driving force that dynamically renders different UI.

Now that we have a brief understanding of client-side routing and SPAs, let’s get an overview of what we’ll be working on!

Case Study: Pokémon

The app we aim to construct is a simple Pokémon app that displays details of a particular Pokémon based on the URL route.

The application will have three unique URL routes: /charizard, /blastoise, and /venusaur. Based on the URL route entered, a different Pokémon will be shown:

In addition, footer links exist at the bottom of the application to direct the user to each respective route upon click:

Do We Even Need Routing for This?

For simple applications like this, we don’t necessarily need a client-side router to make our app functional. This particular app could be composed of a simple parent-child component hierarchy that uses Vue props to dictate the information that should be displayed. Here’s a Pen that shows just this:

See the Pen Vue Pokemon by Hassan Dj (@itslit) on CodePen.

Though the app would functionally work, it misses a substantial feature that’s expected from most web applications—responding to browser navigation events. We’d want our Pokémon app to be accessible and to show different details for different pathnames: /charizard, /blastoise, and /venusaur. This would allow users to refresh different pages and keep their location in the app, bookmark the URLs to come back to later, and potentially share the URL with others. These are some of the main benefits of creating routes within an application.

Now that we have an idea of what we’ll be working on, let’s start building!

Preparing the App

The easiest way to follow along step-by-step (if you wish to do so) is to clone the GitHub repo I've set up.

Download on GitHub

When cloned, install the project dependencies with:

npm install

Let’s take a brief look within the project directory.

$ ls
README.md
index.html
node_modules/
package.json
public/
src/
static/
webpack.config.js

There also exists the hidden files, .babelrc and .gitignore within the project scaffold.

This project is a simple webpack-configured application scaffolded with vue-cli, the Vue command line interface.

index.html is where we declare the DOM element—#app— with which we'll use to mount our Vue application:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.5.3/css/bulma.css">
    <link rel="stylesheet"
      href="../public/styles.css" />
    <title>Pokémon - Routing</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="/dist/build.js"></script>
  </body>
</html>

In the <head> tag of the index.html file, we introduce Bulma as our application’s CSS framework and our own styles.css file that lives in the public/ folder.

Since our focus is on the usage of Vue.js, the application already has all the custom CSS laid out.

The src/ folder is where we’ll be working directly from:

$ ls src/
app/
main.js

src/main.js represents the starting point of our Vue application. It’s where our Vue instance is instantiated, where we declare the parent component that is to be rendered, and the DOM element #app with which our app is to be mounted to:

import Vue from 'vue';
import App from './app/app';

new Vue({
  el: '#app',
  render: h => h(App)
});

We’re specifying the App component, from the src/app/app.js file, to be the main parent component of our application.

In the src/app directory, there exists two other files - app-custom.js and app-vue-router.js:

$ ls src/app/
app-custom.js
app-vue-router.js
app.js

app-custom.js denotes the completed implementation of the application with a custom Vue router (i.e. what we'll be building in this article). app-vue-router.js is a completed routing implementation using the vue-router library.

For the entire article, we’ll only be introducing code to the src/app/app.js file. With that said, let’s take a look at the starting code within src/app/app.js:

const CharizardCard = {
  name: 'charizard-card',
  template: `
    <div class="card card--charizard has-text-weight-bold has-text-white">
      <div class="card-image">
        <div class="card-image-container">
          <img src="../../static/charizard.png"/>
        </div>
      </div>
      <div class="card-content has-text-centered">
        <div class="main">
          <div class="title has-text-white">Charizard</div>
          <div class="hp">hp 78</div>
        </div>
        <div class="stats columns is-mobile">
          <div class="column">&#x1f525;<br>
            <span class="tag is-warning">Type</span>
          </div>
          <div class="column center-column">199 lbs<br>
            <span class="tag is-warning">Weight</span>
          </div>
          <div class="column">1.7 m <br>
            <span class="tag is-warning">Height</span>
          </div>
        </div>
      </div>
    </div>
  `
};

const App = {
  name: 'App',
  template: `
    <div class="container">
      <div class="pokemon">
        <pokemon-card></pokemon-card>
      </div>
    </div>
  `,
  components: {
    'pokemon-card': CharizardCard
  }
};

export default App;

Currently, two components exist: CharizardCard and App. The CharizardCard component is a simple template that displays details of the Charizard Pokémon. The App component declares the CharizardCard component in its components property and renders it as <pokemon-card></pokemon-card> within its template.

We currently only have static content with which we’ll be able to see if we run our application:

npm run dev

And launch localhost:8080:

To get things started, let’s introduce two new components: BlastoiseCard and VenusaurCard that contains details of the Blastoise and Venusaur Pokémon respectively. We can lay out these components right after CharizardCard:

const CharizardCard = { 
  // ... 
};

const BlastoiseCard = {
  name: 'blastoise-card',
  template: `
    <div class="card card--blastoise has-text-weight-bold has-text-white">
      <div class="card-image">
        <div class="card-image-container">
          <img src="../../static/blastoise.png"/>
        </div>
      </div>
      <div class="card-content has-text-centered">
        <div class="main">
          <div class="title has-text-white">Blastoise</div>
          <div class="hp">hp 79</div>
        </div>
        <div class="stats columns is-mobile">
          <div class="column">&#x1f4a7;<br>
            <span class="tag is-light">Type</span>
          </div>
          <div class="column center-column">223 lbs<br>
            <span class="tag is-light">Weight</span>
          </div>
          <div class="column">1.6 m<br>
            <span class="tag is-light">Height</span>
          </div>
        </div>
      </div>
    </div>
  `
};

const VenusaurCard = {
  name: 'venusaur-card',
  template: `
    <div class="card card--venusaur has-text-weight-bold has-text-white">
      <div class="card-image">
        <div class="card-image-container">
          <img src="../../static/venusaur.png"/>
        </div>
      </div>
      <div class="card-content has-text-centered">
        <div class="main">
          <div class="title has-text-white">Venusaur</div>
          <div class="hp hp-venusaur">hp 80</div>
        </div>
        <div class="stats columns is-mobile">
          <div class="column">&#x1f343;<br>
            <span class="tag is-danger">Type</span>
          </div>
          <div class="column center-column">220 lbs<br>
            <span class="tag is-danger">Weight</span>
          </div>
          <div class="column">2.0 m<br>
            <span class="tag is-danger">Height</span>
          </div>
        </div>
      </div>
    </div>
  `
};

const App = { 
  // ... 
};

export default App;

With our application components established, we can now begin to think how we’ll create routing between these components.

router-view

To establish routing, we’ll start by buiding a new component that holds the responsibility to render a specified component based on the app’s location. We’ll create this component in a constant variable named View.

Before we create this component, let’s see how we might use it. In the template of the App component, we’ll remove the declaration of <pokemon-card> and instead render the upcoming router-view component. In the components property; we’ll register the View component constant as <router-view> to be declared in the template.

const App = {
  name: 'App',
  template: `
    <div class="container">
      <div class="pokemon">
        <router-view></router-view>
      </div>
    </div> 
  `,
  components: {
    'router-view': View
  }
};

export default App;

The router-view component will match the correct Pokémon component based on the URL route. This matching will be dictated in a routes array that we’ll create. We’ll create this array right above the App component:

const CharizardCard = { 
  // ... 
};
const BlastoiseCard = { 
  // ... 
};
const VenusaurCard = { 
  // ... 
};

const routes = [
  {path: '/', component: CharizardCard},
  {path: '/charizard', component: CharizardCard},
  {path: '/blastoise', component: BlastoiseCard},
  {path: '/venusaur', component: VenusaurCard}
];

const App = { 
  // ... 
};

export default App;

We’ve set each Pokémon path to their own respective component (e.g. /blastoise will render the BlastoiseCard component). We’ve also set the root path / to the CharizardCard component.

Let’s now begin to create our router-view component.

The router-view component will essentially be a mounting point to dynamically switch between components. One way we can do this in Vue is by using the reserved <component> element to establish Dynamic Components.

Let’s create a starting point for router-view to get an understanding of how this works. As mentioned earlier; we’ll create router-view within a constant variable named View. So with that said, let’s set up View right after our routes declaration:

const CharizardCard = { 
  // ... 
};
const BlastoiseCard = { 
  // ... 
};
const VenusaurCard = { 
  // ... 
};

const routes = [
  // ...
];

const View = {
  name: 'router-view',  
  template: `<component :is="currentView"></component>`,  
  data() {  
    return {  
      currentView: CharizardCard  
    }
  }
}; 

const App = {
// ... 
};

export default App;

The reserved <component> element will render whatever component the is attribute is bound to. Above, we’ve attached the is attribute to a currentView data property that simply maps to the CharizardCard component. As of now, our application resembles the starting point by displaying CharizardCard regardless of what the URL route is.

Though router-view is now appropriately rendered within App, it’s not currently dynamic. We need router-view to display the correct component based on the URL pathname upon page load. To do this, we’ll use the created() hook to filter the routes array and return the component that has a path that matches the URL path. This would make View look something like this:

const View = {
  name: 'router-view',  
  template: `<component :is="currentView"></component>`,  
  data() {  
    return {  
      currentView: {}  
    }
  },
  created() {
    this.currentView = routes.find(
      route => route.path === window.location.pathname
    ).component;
  }
};

In the data function, we’re now instantiating currentView with an empty object. In the created() hook, we’re using JavaScript’s native find() method to return the first object from routes that matches route.path === window.location.pathname. We can then get the component with object.component (where object is the returned object from find()).

Inside a browser environment, window.location is a special object containing the properties of the browser’s current location. We grab the pathname from this object which is the path of the URL.

At this stage; we'll be able to see the different Pokémon Card components based on the state of our browser URL!

The BlastoiseCard component now renders at the /blastoise route.

There’s something else we should consider. If a random URL pathname is entered, our app will currently error and present nothing to the view.

To avoid this, let’s introduce a simple check to display a "Not Found" template if the URL pathnamedoesn’t match any path existing in the routes array. We’ll separate out the find() method to a component method named getRouteObject() to avoid repetition. This updates the View object to:

const View = {
  name: 'router-view',  
  template: `<component :is="currentView"></component>`,  
  data() {  
    return {  
      currentView: {}  
    }
  },
  created() {  
    if (this.getRouteObject() === undefined) {
      this.currentView = {
        template: `
          <h3 class="subtitle has-text-white">
            Not Found :(. Pick a Pokémon from the list below!
          </h3>
        `
      };
    } else {
      this.currentView = this.getRouteObject().component;
    } 
  },
  methods: {
    getRouteObject() {
      return routes.find(
        route => route.path === window.location.pathname
      );
    }
  }
};

If the getRouteObject() method returns undefined, we display a "Not Found" template. If getRouteObject()returns an object from routes, we bind currentView to the component of that object. Now if a random URL is entered, the user will be notified:

The "Not Found" view is rendered if the URL pathname does not match any of the values in the routes array.

The "Not Found" template tells the user to pick a Pokémon from a list. This list will be the links we’ll create to allow the user to navigate to different URL routes.

Awesome! Our app is now responding to some external state, the location of the browser. router-view determines which component should be displayed based on the app’s location. Now, we need to construct links that will change the location of the browser without making a web request. With the location updated, we want to re-render our Vue app and rely on router-view to appropriately determine which component to render.

We’ll label these links as router-link components.

router-link

In web interfaces, we use HTML <a> tags to create links. What we want here is a special type of <a> tag. When the user clicks on this tag, we’ll want the browser to skip its default routine of making a web request to fetch the next page. Instead, we just want to manually update the browser’s location.

Let’s compose a router-link component that produces an <a> tag with a special click binding. When the user clicks on the router-link component, we’ll use the browser’s history API to update the browser’s location.

Just like we did with router-view, let’s see how we’ll use this component before we build it.

In the template of the App component, let’s create three <router-link> elements within a parent <div class="pokemon-links"></div> element. Rather than using the href attribute in <router-link>, we’ll specify the desired location of the link using a to attribute. We’ll also register the upcoming router-link component (from a Link constant variable) in the App components property:

const App = {
  name: 'App',
  template: `
    <div class="container">
      <div class="pokemon">
        <router-view></router-view>
  
        <div class="pokemon-links has-text-centered">
          <router-link to="/charizard"></router-link>
          <router-link to="/blastoise"></router-link>
          <router-link to="/venusaur"></router-link>
        </div>
      </div>
    </div>
  `,
  components: {
    'router-view': View,
    'router-link': Link
  }
};

We’ll create the Link object that represents router-link right above the App component. We've established the router-link component should always be given a to attribute (i.e. prop) that has a value of the target location. We can enforce this prop validation requirement like so:

const CharizardCard = { 
 // ... 
};
const BlastoiseCard = { 
  // ... 
};
const VenusaurCard = { 
  // ... 
};

const routes = [ 
  // ... 
];

const View = { 
  // ... 
};

const Link = {
  name: 'router-link',
  props: {
    to: {
      type: String,
      required: true
    }
  }
};

const App = { 
  // ... 
};

export default App;

We can create the template of router-link to consist of an <a> tag with an @click handler attribute. Upon trigger, the @click handler will call a component method, labeled navigate(), that navigates the browser to the desired location. This navigation will occur with the use of the history.pushState() method. With that said, the Link constant object will be updated to:

const Link = {
  name: 'router-link',
  props: {
    to: {
      type: String,
      required: true
    }
  },
  template: `<a @click="navigate" :href="to">{{ to }}</a>`,
  methods: {  
    navigate(evt) {  
      evt.preventDefault();  
      window.history.pushState(null, null, this.to);  
    }
  }
};

Within the <a> tag, we’ve bound the value of the to prop to the element text content with {{ to }}.

When navigate() is triggered, it first calls preventDefault() on the event object to prevent the browser from making a web request for the new location. The history.pushState() method is then called to direct the user to the desired route location. history.pushState() takes three arguments:

  • a state object to pass serialized state information
  • a title
  • the target URL

In our case, there is no state information that’s needed to be passed, so we've left the first argument as null. Some browsers (e.g. Firefox) currently ignore the second parameter, title, hence we’ve left that as null as well.

The target location, the to prop, is passed in to the third and last parameter. Since the to prop contains the target location in a relative state, it will be resolved relative to the current URL. In our case, /blastoise will resolve to http://localhost:8080/blastoise.

If we click any of the links now, we’ll notice our browser updates to the correct location without a full page reload. However, our app will not update and render the correct component.

This unexpected behaviour happens because when router-link is updating the location of the browser, our Vue app is not alerted of the change. We’ll need to trigger our app (or simply just the router-view component) to re-render whenever the location changes.

Though there’s a few ways to accomplish this behaviour, we’ll do this by using a custom EventBus. An EventBus is a Vue instance responsible in allowing isolated components to subscribe and publish custom events between each other.

At the beginning of the file, we’ll import the vue library and create an EventBus with a new Vue() instance:

import Vue from 'vue';

const EventBus = new Vue();

When a link has been clicked, we need to notify the necessary part of the application (i.e. router-view) that the user is navigating to a particular route. The first step is to create an event emitter using the EventBus's events interface in the navigate() method of router-link. We’ll give this custom event a name of navigate:

const Link = {
  // ...,
  methods: {
    navigate(evt) {
      evt.preventDefault();
      window.history.pushState(null, null, this.to);
      EventBus.$emit('navigate'); 
    }
  }
};

We can now set the event listener/trigger in the created() hook of router-view. By setting the custom event listener outside of the if/else statement, the created() hook of View will be updated to:

const View = {
  // ...,
  created() {  
    if (this.getRouteObject() === undefined) {
      this.currentView = {
        template: `
          <h3 class="subtitle has-text-white">
            Not Found :(. Pick a Pokémon from the list below!
          </h3>
        `
      };
    } else {
      this.currentView = this.getRouteObject().component;
    }

    // Event listener for link navigation
    EventBus.$on('navigate', () => {
      this.currentView = this.getRouteObject().component;
    });
  },
  // ...
};

When the browser’s location changes by clicking a <router-link> element, this listening function will be invoked, re-rendering router-view to match against the latest URL!

Great! Our app now navigates appropriately as we click each of the links.

There’s one last thing we need to consider. If we try to use the browser back/forward buttons to navigate through the browser history, our application will not currently re-render correctly. Although unexpected, this occurs because no event notifier is emitted when the user clicks browser back or browser forward.

To make this work, we’ll use the onpopstate event handler.

The onpopstate event is fired each time the active history entry changes. A history change is invoked by clicking the browser back or browser forward buttons, or calling history.back() or history.forward() programmatically.

Right after our EventBus creation, let’s set up the onpopstate event listener to emit the navigate event when a history change is invoked:

window.addEventListener('popstate', () => {  
  EventBus.$emit('navigate');  
});

Our application will now respond appropriately even when the browser navigation buttons are used!

And there we have it! We’ve just built a custom Vue router using an EventBus and dynamic components. Even with the tiny size of our app we can enjoy a noticeable performance improvement. Avoiding a full page load also saves hundreds of milliseconds and prevents our app from "blinking" during the page change.

Conclusion

I love Vue. One reason as to why - it's incredibly easy to use and manipulate Vue components just like we saw in this article.

In the introduction, we mentioned how Vue provides the vue-router library as the official routing library of the framework. We’ve just created simple versions of the same main items that are used in vue-router:

  • routes: the array responsible in mapping components to respective URL pathnames.
  • router-view: the component that renders a specified app component based on the app’s location
  • router-link: the component that allows the user to change the location of the browser without making a web request.

For very simple applications, the routing we’ve built (or a variation thereof like this one built by Chris Fritz) can do the minimal amount of work needed to route our applications.

The vue-router library, on the other hand, is built in a more complicated manner and introduces incredibly useful capabilities, often needed in larger applications like:

Though the vue-router library does come with additional boilerplate, it’s fairly easy to integrate once your application is composed of well isolated and distinct components. If you're interested, you can see the components of vue-router being used to enable routing in this application here.

Hopefully this was as enjoyable to you as it was for me in compiling this post! Thanks for reading!


This article is an adapted (and summarized) segment from the upcoming book, Fullstack Vue, that I’m working on with the Fullstack.io team! Having the opportunity to work with the folks at Fullstack has been nothing short of being a blast. In true Fullstack fashion, the book covers numerous facets of Vue including but not restricted to routing, simple state management, form handling, Vuex, server persistence, and testing. If this is something that piques your interest or if you have any questions at all, follow (or message) me on twitter (@djirdehh)! If the above doesn’t pique your interest, you can still follow me anyway. 😛


Let’s Build a Custom Vue Router is a post from CSS-Tricks

27 Feb 14:52

AMP News

by Chris Coyier
Dan Jones

My main takeaway from this was the AMP Letter. I've added myself.

AMP is controversial, to say the least. Dave and I did a show on it about a year ago that to me felt fairly balanced in addressing some of the issues. Let's cover some recent news and responses.

One thing that isn't usually controversial: it's fast. AMP pages are damn performant. Even that, though, is contentious. Ferdy Christant notes:

Technically correct AMP pages will perform very similar to any non-horrible web page.

The difference between AMP performing instantly and getting numbers ranging from 2–8s as seen above have to be explained.

Part of that answer you can probably guess: the cache is simply very fast. It’s hard to compete with a Google-class CDN.

You don't need AMP to have a fast website.

FYI @CityLab article pages load faster than @nytimes AMP pages. Just to show you do not need AMP to have fast loading pages #webperf pic.twitter.com/34YboEBwLP

— Michael Donohoe (@donohoe) February 23, 2018


The most controversial bit is that carrot offered for using AMP: the search results news carousel. The carousel is extremely prominent in Google search results, and AMP is a one-way ticket to get in. You could make a site faster than AMP, but that doesn't meet the criteria for entry. Tim Kadlec:

there has been no indication of any attempt to address the first issue, that of incentivization and premium placement. In fact, not only has there been no attempt to fix it, it appears the AMP team is doubling-down on those incentives instead.

Doubling-down, as in, AMP stories will be released soon and will also enjoy premium placement on Google. Every indication is that the primary desire of people reaching for AMP is the preferential search results treatment. Gina Trapani:

In my experience people are motivated to use AMP… I’ve seen this from our clients…mostly because of SEO. They want it in that top stories carousel, they want that lightning bolt of approval in regular search results which is happening now.

Of course, Google can do whatever they want. They are an independent company and if they wanna tell us that we have to use a special format to have benefits on their platform, then that's the way it is. It doesn't mean we have to be happy about it. Hundreds of people have signed the AMP letter, which calls for two changes:

  1. Instead of granting premium placement in search results only to AMP, provide the same perks to all pages that meet an objective, neutral performance criterion such as Speed Index. Publishers can then use any technical solution of their choice.
  2. Do not display third-party content within a Google page unless it is clear to the user that they are looking at a Google product. It is perfectly acceptable for Google to launch a “news reader” but it is not acceptable to display a page that carries only third-party branding on what is actually a Google URL, nor to require that third party to use Google’s hosting in order to appear in search results.

Ethan Marcotte is concerned:

absent action from some sort of regulatory body, I’m not sure what influence you or I could exert to change the trajectory of AMP

...but thinks we could perhaps collectively have influence. Jeremy Keith has called some of the messaging behind AMP an outright lie:

I don’t think the developers working on the AMP format are intentionally deceptive (although they are engaging in some impressive cognitive gymnastics). The AMP ecosystem, on the other hand, that’s another story—the preferential treatment of Google-hosted AMP pages in the carousel and in search results; that’s messed up.

Jeremy also notes that the power Google is exerting here is worrisome. Part of the stated motivation is trying to fix the web. Taking a stand, as it were.

I remember feeling very heartened to see WikiPedia, Google and others take a stand on January 18th, 2012 (against SOPA and PIPA). But I also remember feeling uneasy. In this particular case, companies were lobbying for a cause I agreed with. But what if they were lobbying for a cause I didn’t agree with? Large corporations using their power to influence politics seems like a very bad idea. Isn’t it still a bad idea, even if I happen to agree with the cause?

Cloudflare quite rightly kicked The Daily Stormer off their roster of customers. Then the CEO of Cloudflare quite rightly wrote this in a company-wide memo:

Literally, I woke up in a bad mood and decided someone shouldn’t be allowed on the Internet. No one should have that power.

There’s an uncomfortable tension here.

AMP is also expanding to other technology, notably email. Well, Gmail, that is. Fast, well-rendering, interactive emails seem like a hugely positive thing. Perhaps predictably at this point, people in that industry have similar concerns. Jason Rodriguez:

I’m an email guy. I’ve written three books on email, spoken at a bunch of conferences on the topic, and help build tools for other email folks at my day job. I love seeing the email platform grow and evolve. I love seeing people working on interesting ideas that make email more valuable for the subscribers that receive them.

So, you’d think I’d be thrilled by Google’s announcement about adding dynamic content and interactivity to Gmail with AMP for Email. You’d be wrong.

Jason's primary concern being that instead of improving support for what we already have, they've invented a new format and called it open-sourced, but have full control over it. However, with far more blockers in the way (e.g. ESPs not supporting the new MIME type) and less carrots to offer, it seems like a long shot it will happen.

I know I've covered a lot of negative news here, but that's mostly what I've been seeing. Strangely enough, I feel more interested in watching how this all shakes out than I am motivated to weigh in on either side.


AMP News is a post from CSS-Tricks

27 Feb 14:31

Fahrenheit 451

by Jason Kottke
Dan Jones

I don't know how this could be better than the '66 film, but it certainly looks more intense.

Coming to HBO in May is an adaptation of Ray Bradbury’s novel, Fahrenheit 451. It stars Michael B. Jordan and Michael Shannon.

In a future where the media is an opiate, history is rewritten and “firemen” burn books, Jordan plays Guy Montag, a young fireman who struggles with his role as law enforcer and with his “mentor”, played by Shannon.

The book, which got its title from “the temperature at which book paper catches fire, and burns”, begins like so:

It was a pleasure to burn.

It was a special pleasure to see things eaten, to see things blackened and changed. With the brass nozzle in his fists, with this great python spitting its venomous kerosene upon the world, the blood pounded in his head, and his hands were the hands of some amazing conductor playing all the symphonies of blazing and burning to bring down the tatters and charcoal ruins of history. With his symbolic helmet numbered 451 on his stolid head, and his eyes all orange flame with the thought of what came next, he flicked the igniter and the house jumped up in a gorging fire that burned the evening sky red and yellow and black. He strode in a swarm of fireflies. He wanted above all, like the old joke, to shove a marshmallow on a stick in the furnace, while the flapping pigeon-winged books died on the porch and lawn of the house. While the books went up in sparkling whirls and blew away on a wind turned dark with burning.

The previous film adaptation was by Francois Truffaut in 1966, who cast Julie Christie in two of the main roles. It was Truffaut’s only English-language film and the first one in color.

Tags: books   Fahrenheit 451   Michael B. Jordan   Michael Shannon   movies   trailers   video
26 Feb 20:50

We’re all addicted to the smartphone slot machines in our pockets

by Jason Kottke

In a new video series for Vox, Christophe Haubursin talks to Tristan Harris, a former Design Ethicist at Google, about how our phones and apps are designed to be addictive and some strategies for breaking their hold on us:

1. Turn off all non-human notifications.
2. Change your screen to grayscale.
3. Restrict your home screen to everyday tools.

Ezra Klein recently did an interview with Harris that includes more of his views on the ethics of technology, phones, and social media.

Silicon Valley is reckoning with having had a bad philosophical operating system. People in tech will say, “You told me, when I asked you what you wanted, that you wanted to go to the gym. That’s what you said. But then I handed you a box of doughnuts and you went for the doughnuts, so that must be what you really wanted.” The Facebook folks, that’s literally what they think. We offer people this other stuff, but then they always go for the outrage, or the autoplaying video, and that must be people’s most true preference.

Tags: Christophe Haubursin   Ezra Klein   Tristan Harris   video
26 Feb 20:50

#1691 – Cool show

by Chris

#1691 – Cool show

26 Feb 20:50

It’s good to have experience

by CommitStrip

26 Feb 15:49

Code Golf

I also enjoy Reverse Regular Golf. I've been playing for years all across the country and I'm still on the first hole.
26 Feb 15:49

Every Stan Lee Marvel Cameo

Every Stan Lee Marvel Cameo

 

Check out every Stan Lee cameo in a Marvel movie since 1989 (excluding Black Panther since it's not online yet)...

CLICK THE IMAGE FOR FULL VIEW!

Every Stan Lee Marvel Cameo

Source: l_l_l-illiam

Follow us on:
 

February 25 2018
26 Feb 15:49

CodeSOD: Waiting for the Future

by Remy Porter

One of the more interesting things about human psychology is how bad we are at thinking about the negative consequences of our actions if those consequences are in the future. This is why the death penalty doesn’t deter crime, why we dump massive quantities of greenhouse gases into the atmosphere, and why the Y2K bug happened in the first place, and why we’re going to do it again when every 32-bit Unix system explodes in 2038. If the negative consequence happens well after the action which caused it, humans ignore the obvious cause and effect and go on about making problems that have to be fixed later.

Fran inherited a bit of technical debt. Specifically, there’s an auto-numbered field in the database. Due to their business requirements, when the field hits 999,999, it needs to wrap back around to 000,001. Many many years ago, the original developer “solved” that problem thus:

function getstan($callingMethod = null)
{

    $sequence = 1;

    // get insert id back
    $rs = db()->insert("sequence", array(
        'processor' => 'widgetsinc',
        'RID'       => $this->data->RID,
        'method'    => $callingMethod,
        'card'      => $this->data->cardNumber
    ), false, false);
    if ($rs) { // if query succeeded...
        $sequence = $rs;
        if ($sequence > 999999) {
            db()->q("delete from sequence where processor='widgetsinc'");
            db()->insert("sequence",
                array('processor' => 'widgetsinc', 'RID' => $this->data->RID, 'card' => $this->data->cardNumber), false,
                false);
            $sequence = 1;
        }
    }

    return (substr(str_pad($sequence, 6, "0", STR_PAD_LEFT), -6));
}

The sequence table uses an auto-numbered column. They insert a row into the table, which returns the generated ID used. If that ID is greater than 999,999, they… delete the old rows. They then insert a new row. Then they return “000001”.

Unfortunately, sequences don’t work this way in MySQL, or honestly any other database. They keep counting up unless you alter or otherwise reset the sequence. So, the counter keeps ticking up, and this method keeps deleting the old rows and returning “000001”. The original developer almost certainly never tested what this code does when the counter breaks 999,999, because that day was so far out into the future that they could put off the problem.

Speaking of putting off solving problems, Fran also adds:

For the past 2 years this function has been returning 000001 and is starting to screw up reports.

Broken for at least two years, but only now is it screwing up reports badly enough that anyone wants to do anything to fix it.

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!
26 Feb 15:49

The Legend of Link

The Legend of Link So in this role reversal world of Hyrule, is Ganondorf still a male or is he now a female?

source: deviantART


See more: The Legend of Link
26 Feb 13:46

Google Assistant is learning new Routines and languages

by Evan Selleck

Back in October of last year, Google officially announced that Google Assistant, the digital assistant that is getting baked into as many different devices as possible, would learn new Routines to help get tasks done faster.

Today Google announced that Routines are coming soon. Google says it is adding support for six Routines to start, and users can take a crack at them beginning next week. What this means is that users will be able to have Assistant handle a handful of separate tasks with a single command.

So when you walk into your home and say, “Hey, Google, I’m home”, the digital assistant can not only turn on the lights, but also start playing music, share some important reminders, and more.

Location-based reminders are also coming to Google Assistant on smart speakers. So if you tell Google Home that you need to be reminded to get some milk when you get to the grocery store and swing into the parking lot, Assistant should let you know on your phone that you need to pick up some milk.

If that isn’t enough, Google also announced that it is working with hardware manufacturers and wireless carriers to get even more Assistant integration out there in the wild. For manufacturers, this means that Assistant could be used to launch specific features on a phone, even one from a third-party manufacturer like LG (which has already voiced its support for this initiative). So you could tell Assistant to launch the camera in a specific filter, rather than having to launch the app yourself and find the filter you want.

As for the carrier integration, it could mean that you can ask Google Assistant how much data remains on your monthly allotment, or other carrier-specific queries of that ilk.

Finally, language support. Google announced that Assistant will offer support for 30 languages by the end of 2018. When it launched, it only supported one — English — and right now the digital assistant supports Japanese, French, German, Spanish, Korean, Italian, and Brazilian Portuguese. Google says that offering 30 different languages covers 95 percent of Android users, so while they don’t plan to stop at only 30 languages, that’s a good place to aim.

Multilingual individuals won’t have to pick just one language when using Google Assistant, either. So if you speak more than one of the supported languages, you will be able to switch back and forth and Assistant should be able to keep up with you.

What do you think of Assistant’s new changes?

26 Feb 13:46

Call Support

Call Support When was the last time you actually saw a payphone in the wild?



See more: Call Support
23 Feb 19:57

“Even the Stiffest People Can Do the Splits”

by Jason Kottke

Eiko Splits

In Japan, the current cultural successor to The Life-Changing Magic of Tidying Up is Even the Stiffest People Can Do the Splits, a book by “world-renowned yoga teacher” Eiko that promises to teach anyone how to do the splits in just four weeks.

Whether you spend your days running marathons or slouching over a keyboard, everyone can benefit from stretching and the increased flexibility that comes along with it. With only five minutes of stretching a day, you’ll be doing perfect splits in four weeks and experiencing a host of health benefits such better circulation, fewer joint injuries, toned muscles, improved balance, and much more!

As a keyboard sloucher who has been not getting enough exercise, I am tempted to try this, if only to surprise my kids with some stealth flexibility. (via ny times)

Tags: books   Eiko   Even the Stiffest People Can Do the Splits
23 Feb 16:47

Call Them Like You See Them.

You can't watch where you're going if you're going nowhere.
23 Feb 14:08

Always Double Check

by alex

Always Double Check

23 Feb 14:08

The Simpsons

In-universe, Bart Simpson and Harry Potter were the same age in 1990. Bart is perpetually 10 years old because of a spell put on his town by someone trying to keep him from getting his Hogwarts letter.
22 Feb 15:46

CodeSOD: Functional IsFunction

by Remy Porter

Julio S recently had to attempt to graft a third-party document viewer onto an internal web app. The document viewer was from a company which specialized in enterprise “document solutions”, which can be purchased for enterprise-sized licensing fees.

Gluing the document viewer onto their internal app didn’t go terribly well. While debugging, and browsing through the vendor’s javascript, he saw a lot of calls to a function called IsFunction. It was loaded from a “utilities.js”-type do-everything library file. Curious, Julio pulled up the implementation.

function IsFunction ( func ) {
    var bChk=false;
    if (func != "undefined") bChk=true;
    else bChk=false;
    return bChk;
}

I cannot emphasize enough how beautiful this block of code is, by the standards of bad code. There’s so much there. One variable, bChk uses Hungarian notation. Nothing else seems to. It’s a totally superfluous variable, as we could just do return func != "undefined".

Then again why would we even do that? The real beauty, though, is how the name of the function and its implementation have no relationship to each other, and the implementation is utterly useless. For example:

IsFunction("Hello World"); //true
IsFunction({spam: "eggs"}); //true
IsFunction(function() {}); //true, but it was probably an accident
IsFunction(undefined); //true
IsFunction("undefined"); //false

Yes, the only time this function returns false is the specific case where you pass it the string “undefined”. Everything else IsFunction apparently. The useless function sounds important. Someone wrote it, probably as a quick attempt at vaguely defensive programming. “I should make sure my inputs are valid”. They didn’t test it. The certainly didn’t think about it. But they wrote it. And then someone else saw the function in use, and said, “Oh… I should probably use that, too.” Somewhere, there’s probably a “Style Guide”, which mandates that, before attempting to invoke a variable that should contain a function, you use IsFunction to confirm it does. It comes up in code reviews, and code has been held from going into production because someone didn't use IsFunction.

And Julio probably is the first person to actually check the implementation since it was first written.

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!
22 Feb 15:46

How to Apply Instagram Filters in the Browser Using Pure CSS

by Adi Purdila

Welcome to another Envato Tuts+ quick tip; in today’s video we’re going to talk about Instagram filters. If you’re an Instagram user (and probably even if you’re not) you’ll be aware that it offers you various different filters which you can apply to a photo you’re uploading. Nowadays you can achieve similar results in the browser using nothing more than CSS. Let’s take a look!

Watch Screencast

 

Instagram.css

Instagram.css is a library, available on Github, which does all the heavy lifting for you. Download it, then add it to your web page (or as an asset pulled into a CodePen pen). 

Our markup looks a little like this:

<div class="demo-container">
  <figure>
    <img src="boat.jpg">
  </figure>
</div>

We have a demo-container which we’re using purely for positioning the image centrally. The <img> tag is wrapped in a <figure>, and it’s to that <figure> that we’re going to add some classes. 

Adding a filter- Class

There are currently over forty filters available, all listed on the Github page. Here are one or two examples you can try yourself in the embedded pen below:

  • 1977 filter-1977
  • Helena filter-helena
  • Kelvin filter-kelvin
  • Moon filter-moon
  • Poprocket filter-poprocket
  • Reyes filter-reyes
  • Sierra filter-sierra
  • Toaster filter-toaster
  • Valencia filter-valencia
  • Walden filter-walden

How Does it Work?

If you open up the unminified version of instagram.css you’ll see that each class applies the CSS filter property, like this for example:

.filter-1977 {
  filter: sepia(.5) hue-rotate(-30deg) saturate(1.4);
}

Others go a step further and add blend-modes to a pseudo element positioned above the image:

.filter-amaro::before {
  background: rgba(125, 105, 24, .2);
  content: "";
  mix-blend-mode: overlay;
}

The values applied to filter and mix-blend-mode alter the channels, saturation, and brightness of the image, combining to give us the Instagram-like effects. These are pretty powerful effects too, previously only possible in the browser with SVG. 

Browser Support

CSS filters are reasonably well supported in modern browsers, including the latest version of Edge (13+). IE doesn’t offer support, and neither does IE Mobile. Take a look at CanIUse for more details.

Conclusion

That’s it for this quick tip; instagram.css offers a really rapid way to apply some cool effects to your images in the browser. Go and download it, play with it, and pull it apart to apply your own filters and effects.

Learn More About CSS Blending and Filtering

22 Feb 14:53

Know

by Reza

22 Feb 14:53

Yourself

by Reza

22 Feb 14:53

Comic for 2018.02.21