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 /randomto 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.