yequari.com

I write code and occasionally blog posts.

Recreating the Windows Live Messenger Avatar in CSS

This past week I’ve been working on a big redesign of my site. I’m trying to recreate the vibe of MSN / Windows Live Messenger around 2008-2011. Today, I spent most of the day recreating the avatar frame from WL Messenger in CSS.

At first, I was trying really hard to recreate the kind of squircle🔗 shape from the login screen. It turns out this is quite difficult in CSS, and the only way I could possibly have done it is through creating an SVG path that I could use to clip the HTML element, but then I would lose access to the border and box-shadow properties. So instead I opted to just make a rounded square, using the first-radius value to round the corners with an ellipse shape rather than a circle. After all, we’re going for the vibe, not a 1:1 recreation. After hours of tinkering with just the shape, I added the gradient background, as well as a <span> on top of everything to add the “glossy” effect. You can see the code on CodePen🔗.

Next, I wanted to make it dynamic. If I haven’t uploaded to my blog in a week, my avatar should show me as “away.” My first attempt used JavaScript, which required me to put the date of my recent posts on my index page. I came up with the following script.

/* js/avatar.js */
let latest = document.querySelector('.dt-published');
let avatar = document.querySelector('#avatar-frame');

let latestDate = Date.parse(latest.attributes.getNamedItem('datetime').value);
let threshold = new Date();
threshold.setDate(threshold.getDate() - 7);

console.log(latestDate)

if (latestDate < threshold) {
  avatar.className = 'busy';
} else {
  avatar.className = 'online';
}

It worked great on the index. But as soon as I navigated to another page, it broke. My avatar is present on every page in the sidebar, but not every page has a <time> element on it, and of those that do, only one displays the date of my latest blog post. I’d have to find some other way.

Next I tried doing this with Hugo templates. Since my latest blog post would be generated at the same time as the rest of the site, I could calculate the difference once then not worry about the JavaScript at all.

  <!--partials/sidebar.html-->
  {{ range first 1 (where .Site.RegularPages.ByDate.Reverse "Section" "blog") }}
      {{ $d1 := time.ParseDuration "-168h" }}
      {{ $t1 := time.Now.Add $d1 }}
      {{ $t2 := time.AsTime .PublishDate }}
      {{ if $t2.After $t1 }}
          <div id="avatar-frame" class="online">
      {{ else }}
          <div id="avatar-frame" class="busy">
      {{ end }}
  {{ end }}

I wrote all this code before I figured out the fatal flaw in my genius plan: unless I generate my site every day, the frame color will not change, since it is determined at the time of generation. Automatically doing this wouldn’t be difficult, but it is a waste of compute time.

So, back to JavaScript. I need some way to keep track of my latest publish date that is available on all pages. I figure the footer is a good spot for this. Using Hugo template functions, I grab the latest blog post and print its publish date.

<!-- partials/footer.html -->
<p>
    {{ range first 1 (where .Site.RegularPages.ByDate.Reverse "Section" "blog") }}
        Last updated <time id="last-update" datetime="{{ .PublishDate }}">{{ .PublishDate.Format "January 2, 2006" }}</time>.
    {{ end }}
</p>

Then I update the first line of my JavaScript, and it all works!

/* js/avatar.js */
let latest = document.querySelector('#last-update');

Graphic design is not at all my strong suit (despite my random sidebar quote sometimes saying it is my passion), so it has been an enjoyable experience challenging myself to create all of the assets and styles for my new site layout. I’m learning so much and I’m excited to show it all off in the near future!