How to make a Dashboard Widget with Flask and jQuery

I love Dribbble a whole lot. It’s tagline is show and tell for designers, which I wholeheartedly disagree with — as someone whose design abilities pretty much start and end at CSS, it’s still refreshing to peruse such an incredible breadth of images. Dribbbble users submit 400x300 images as ‘shots’ — they can be screenshots of a work-in-progress, brainstorm refuse for a rebranding campaign, or general flexing of chops as seen below:

Browsing Dribbble shots gives me a great deal of inspiration (and envy), but I found myself yearning for an easier approach than navigating to the site and perusing. I also get myself using my MacBook’s Dashboard Widgets more often, so I strived to create a widget for myself that would display a popular ‘shot’ at random.

The end result: layup.jmduke.net. Once I understood exactly what I needed to do, the implementation was simple — this is a short blog post documenting how I approached the app and what I found out.

So what is a Widget?

Dashboard Widgets were introduced in OS X: Tiger to fill that weird mini-application niche which was oddly prevalent in 2005. Ever since then, they’ve been relegated to the sidelines a little bit, but I think they’re still a great way to grab all of the stuff I like to check occassionally without getting side-tracked endlessly. (I go on twitter to check if I’ve gotten any new mentions; twenty minutes later, I emerge from a long-form post about Objective-C, hopeless and weary.)

The applications might be branded as ‘widgets’, but essentially, the Dashboard is a bunch of tiny browsers: they can either be pointed towards locally stored .wdgt packages (which contain HTML, CSS, JavaScript, and a bunch of metadata that I don’t feel like dealing with) or be invoked as a Web clip (essentially a glorified <iframe>) which grabs a specific location on a specific web page and report the results.

I decided to go with the second route for one important reason: I was lazy. I didn’t want to have to deal with cross-domain requests in javascript; I didn’t want to have to deal with weird Dashboard Widget metadata that I’d never need to use again; I didn’t want to have to deal with strange distribution protocols. I wanted to make this quickly, intelligently, and lazy.

I started with the important stuff: grabbing the images.

Dribbble’s API

There’s really not much to report here. Dribbble makes it gloriously simple to access their API — I grabbed the GET /shots/:list method and threw it at Requests (if you’re not using Requests to deal with HTTP in Python, you’re doing it wrong) —

random_page = random.randint(0, 5)
api_url = 'http://api.dribbble.com/shots/popular?per_page=30&page=%s' % random_page
json_data = requests.get(api_url).json
images = [shot['image_url'] for shot in json_data['shots']]
return images[random.randint(0, len(images) - 1)]

Building the Front-end

I used Flask, and it was as basic as it could get:

  • redirect GET /random to the above method
  • redirect GET /to display an image which gets it’s source from the above method.

My original methodology was simple: upon clicking the image, it would refresh the page, randomly displaying a new image. This was elegant and happy and perfect except it didn’t work: clicking on the image in the dashboard would open it as a new window, pretty much destroying the whole point.

Instead, I went for a jquery solution:

<script>
    $("img").click(function() {
        $.get('/random', function(data) {
            $("img").attr("src", data);
        });
    });
</script>

Click on the image and it changes the source of the image to a new random URL. Same concept, much better execution — and it works perfectly! (Note: when you’re throwing an in-line script such as the one above, be sure to include it after the DOM elements its referencing. Originally, I had that script above the <img> tag, and I spent entirely too much time not realizing why it wasn’t doing anything.)

Conclusion

A bit better at jQuery, a (slightly) better understanding of my operating system, and a pretty product. Not a bad way to kill three hours.

Things I’d still like to do, given infinite time:

  • Release this under GitHub. It’s currently very ugly in terms of source (literally, the HTML template is just a hard-coded string in app.py) so that would give me impetus to clean it up out of sheer embarassment.
  • Prettify the page. A nice font-face, a nice background, social media jank, the works.
  • Make it more language-agnostic. I love the fact that I can throw up a web app and it instantly doubles as a Dashboard Widget (given certain screen space), but being able to tailor this towards Windows would be wonderful too.

If you liked this post, you should follow me on Twitter.

  1. voigtlander reblogged this from justyduke
  2. justyduke posted this