Valentin Jacquemin

Style it, ship it

As getting the data from Strava and transforming it is now solved, what’s left is styling the spakline and making it part of an automated publishing process.

By using sal and jq as explained in the last 2 articles, I get a list of points. I can simply visualize the those points, as a sparkline, like so:

<svg>
   <polyline transform="translate(0,30), scale(1, -1)"
      points="0,5 3,8 6,6 9,6 12,7 15,5 18,3 21,11 24,2 27,11 30,8 33,11 36,12 39,13 42,7 45,15 48,5 51,14 54,16 57,21 60,13 63,21 66,21 69,24 72,11 75,6 78,8 81,8 84,5 87,15 90,5 93,4 96,3 99,4 102,2 105,3 108,3 111,4 114,2 117,2 120,4 123,4 126,3 129,3 132,6 135,4 138,8 141,6 144,8 147,7 150,6 153,6"
      fill="transparent"
      stroke="#aaa">
   </polyline>
</svg>

I simplified a tiny bit but the important part is those points. These are what the jq transformation outputs.

And this renders like this:

As cool as it is, there’s still some work!

CSS Layout and Styles

I wanted to have the sparkline in the footer of my running blog, taking more space than that, actually the full viewport’s width.

So I started to brainstorm on Codepen. I obviously took inspiration in what GitHub did on its repositories page. Making the sparkline itself bigger, with some text around is nothing difficult. I just had to find the colors and dimensions I wanted. For the colors, I ended up with something close to what Strava uses.

To make it span the entire width of the viewport, I then used flex ability to stretch an element. By duplicating the first and last points of the sparkline and then put them in their own svg element, it’s been easy to stretch those 2 points at the beginning and at the end of the sparkline to give a sense of continuity.

Web Developer tools showing each flex item with an overlay. The sparkline in the center and the equally stretched sections on the sides.

Automate the whole process

runboyrun.ch used to run on an EC2 instance of Ghost. In the meantime, I slightly adapted the setup. I’m still using ghost but only locally to manage all my posts. By locally, I mean on my home network, it actually runs on a lightweight Lenovo laptop which runs as my cost friendly homelab.

The version publicly available is hosted on AWS S3 with Cloudfront as CDN. Again, more cost friendly, but makes more sense overall too.

That being said, I have my custom machinery to push new versions of that blog to S3. Nothing fancy, a bash script that’s polling the latest version of the blog from the local ghost instance and using the AWS cli to interact with S3 and Cloudfront to publish the new content and invalidate the CDN caches. Now on top of that, I integrated all the elements I just explained.

Every morning, a cron job executes that script which uses sal to fetch the latest Strava activities. On my homelab server, sal uses a valid state.json file to make the execution non interactive. Check out the previous article if needed, I described how this file is used and where it’s stored.

Then jq to transform the Strava activities into a series of points that are then added to the blog content via a m4 include macro.

I quite like this solution and honestly I love checking out runboyrun.ch the next day of a run. That’s just one more thing that keeps me motivated to keep that line moving and that yearly distance above 1000 kilometers.

It’s been a fun side project.

Also on: Bluesky Mastodon