Michael Su's Blog

Hello 世界!

Hello hello! For better or worse, you have landed on my inaugural post on this blog. It's exciting to have a blank canvas to profane with my thoughts. Let's start with how I built this site.

Blank Canvas

The Process

It was nice to flex my right brain and design for this project, since I was a developer at my last job. My process was as follows:

  1. Draw notepad sketches for layout ideas
  2. Prototype website in the browser
  3. Draw assets with my Wacom or take pictures with my Canon
  4. Code up a static site generator to organize the project
  5. Create the deployment scripts

Pen and paper is the best way to explore ideas in my opinion. It just doesn't constrain your creativity. After I'm satisfied with my sketches, I go straight into HTML/CSS for higher fidelity prototypes. Sometimes, I will go into Sketch to flesh out ideas if the site's structure is more complicated but I didn't feel the need to for this site.

When creating the assets, I was actually pleasantly surprised with how my drawing turned out on the Wacom. When I first used it, I found it hard to control the nib and get the lines I wanted. It takes awhile to get used to looking at the screen while drawing on the tablet. I am still not quite satisfied with my control with the tablet but I'm sure it will just get better as I draw more for this site.

Afterwards, I wrapped the HTML prototype with a site generator to generate the other pages. Finally, I wrote two simple bash scripts to upload my homepage to Github Pages and the blog to Google Cloud Storage.

My workspace (minus the PC next to the monitor and the Wacom)

Technical Details

Feel free to skip ahead to the next section if you're not interested in the techie nitty gritty :)

Both my homepage and blog are based on the static generator described by Nicolas Parriault here. In addition to his basic generator, I added webassets for asset compilation, an Atom feed generator, and an html minifier. I'll skip the basic generator that Nicolas describes and talk about the additions.

On the front end I wanted to separate my javascript files by logic and wanted to minimize asset size to provide readers a speedy experience. To that end, I used webassets because I was familiar with it and the htmlmin package (django-htmlmin was choking on Chinese characters).

from flask.ext.assets import Environment, Bundle

assets = Environment(app)
assets.load_path = ["source"]
assets.cache = ".webassets-cache"

# Webasset Bundles
styles = Bundle(
    "scss/styles.scss",
    filters="scss",
    output="css/styles.css")
js = Bundle(
    "js/main.js",
    "js/more.js",
    filters="closure_js",
    output="js/main.js")

assets.register("styles", styles)
assets.register("js", js)

For htmlmin, I wrote a small helper function that renders the template without minification during debug but minifies during builds.

from htmlmin import minify

# Helpers
def render(*args, **kwargs):
    if is_build:
        return minify(render_template(*args, **kwargs))
    return render_template(*args, **kwargs)

I also wanted a feed and found the feedgen package which provides a FeedGenerator class. The code is pretty straight forward although I had to read up on the Atom spec.

@app.route("/feed/")
def feed():
    feed = FeedGenerator()
    feed.id("blog.yoursite.com")
    feed.title("Your Blog\'s Feed")
    feed.author(dict(name="Your Name", email="your-email@gmail.com"))
    feed.logo("cdn.com/your-logo.png")
    feed.subtitle("Description of your blog")
    feed.link(href="http://blog.yoursite.com/")
    feed.language("en")
    for page in pages:
        page_url = "http://%s/%s/" % ("blog.yoursite.com", url_for("page", path=page.path))
        feed_entry = feed.add_entry()
        feed_entry.id(page_url)
        feed_entry.title(page.meta["title"])
        feed_entry.link(href=page_url)
        publish_date = pacific_timezone.localize(
            datetime.strptime(page.meta["date"], "%B %d, %Y"))
        feed_entry.published(publish_date)
        feed_entry.content(page.html)

    return (feed.atom_str(pretty=True), 200,
            {"Content-Type": "application/atom+xml"})

Bonus! Flatpages also comes with pygment support for those who code.

from flask_flatpages import pygments_style_defs

@app.route("/pygments.css")
def pygments_css():
    return (pygments_style_defs("monokai"),
        200, {"Content-Type": "text/css"})

For the deployment scripts, Nicolas' static site generator uses Flask-FlatPages to create a static build in a build folder so I just git push the build folder for my homepage and rsync my blog to Google Cloud Storage.

Ante up!

The point of this blog is to improve my writing and share my projects with others. I learn best when I jump off the proverbial cliff and start doing. From feedback from you, my writing will naturally improve! ☺ It will also be interesting to see how my projects evolve from people's input. I intend on blogging about:

  • Startups
  • Investing
  • Languages
  • Art – photography, drawing, design
  • And more?

So pick a topic you enjoy and stay tuned! 再見。