A chance encounter with a former co-worker leads to a quick freelance gig that would define my style of work for years to come.
A rock in my parents’ backyard, eight months of acupuncture, and a household chore share a common thread of being the catalyst for thought.
I detail my experience working with Dropbox to build an adaptive website that provides a unique experience across mobile, tablet, and desktop.
Not one to turn down a challenge, I accept a freelance gig with an identical deadline to another job with the same client. Feel the burn-out.
An extended transcription of my CreativeMornings talk about my dad, his work, and how he turned me into the maker I am today.
I collaborated with Casper to build the animations for their new homepage. In this post, I share the story from initial call to launch.
Realizing that a redesign doesn’t mean I need to start from scratch with everything, I reclaim the logo from the previous design to use on the new site.
Eager to build more than the blog, I write about bringing a new content model to the site in the form of an intro on the homepage.
Similar to the post itself, there’s not much to this description besides indicating that I replace the default favicon with my own.
In this post, I second-guess the path to the site’s RSS feed and refactor it to support multiple feeds, which will most likely be overkill in the end.
Taking a break from visible progress, I implement TypeScript on the site as a way for me to finally learn what the big deal is all about.
Rather than moving the needle further, I spend a night going down a rabbit hole that does leave me without much to show, but I still consider it progress.
A dozen posts into writing for the new site, I recognize a need for pagination and write about implementing it in Contentful.
After referencing another post in the form of a link, I find myself needing to build a custom renderer in Contentful.
A friend pointed out a mistake in an earlier post I wrote, so I implemented footnotes to allow for corrections while still maintaining the original writing.
In a move to improve readability, I adjust the leading on the site to provide more breathing room between lines of text.
With the discovery of the ch unit type in CSS and guidance on the ideal character-based line width, I set out to enforce a max-width on the site’s body copy.
With an increasing number of code snippets in my posts, I introduce Prism.js to the site for much improved syntax highlighting.
After fetching WebP formatted images from Contentful’s image API, I realize that Safari doesn’t support WebP and requires a fallback PNG.
A forgotten CSS style prevents the images on the site from resizing for mobile, but a new discovery of Contentful’s image API leads to the perfect max-width.
In order to maintain a chronologically aware blog, I add dates to posts and the RSS feed using the date-fns library.
After realizing that Contentful’s rich text renderer doesn’t include a renderer for assets, I create my own using Contentful’s image API.
To keep myself in check, I install a Lighthouse integration to score the site’s performance and accessibility.
With a description as short as the post itself, I write about adding a site title and links to the article titles.
After being nudged by the elders of the web, I implement an RSS feed for those who are still sour about the demise of Google Reader—myself included.
Neglecting to read the manual, I hit a snag and blame Contentful’s API before inevitably realizing that the problem exists between the keyboard and chair.
In this inaugural post, I set out on an adventure to redesign my site while documenting its process along the way.
After five years of running my own startup, I experience my first panic attack, which leads me to course correct my life in favor of good health and stability.
With only days before the SCA deadline, I launch the new invoice page with to be SCA-ready while also paving the way for more improvements.
Wrapping up my work on the invoice page, I set up integration testing using Cypress to make sure that everything continues to work end-to-end.
Continuing to make progress on the invoice page, I talk about some of the ways I’m improving the codebase along the way.
A chat with a user leads me to consider a subsidized plan for the New Year to help folks through the pandemic.
I pause work on the account page to make sure Cushion’s invoice payment integration is ready for the SCA deadline.
In needing to redesign the pricing page for the new account section, I decide to rethink the structure of Cushion’s existing plans.
An innocent bug report unfolds into a roller coaster ride of a troubleshooting journey.
As I begin building Cushion’s new account page, I start by scaffolding a static version of it and building the components it requires.
With SCA regulation going into effect at the end of the year, I prioritize migrating to the Stripe customer portal, which means redesigning the account section.
After years and years of incrementally tweaking the design of Cushion, I take a holistic look at the layout system.
After redesigning Cushion’s homepage, I take the next step in migrating to Contentful by rethinking the blog.
To keep my mind busy while dealing with a tough time, I distract myself with Cushion’s new homepage animation.
While building Cushion’s new homepage, I go the extra mile to swap out better-fitting images for different breakpoints.
After migrating Cushion’s changelog to Contentful, I move onto the homepage, where I narrow in on an approach to compose pages entirely in the CMS.
In my initial step towards migrating Cushion’s marketing site to Contentful, I start with the changelog.
I reworked the main nav to include invoicing, which was met with a wave of thanks from users.
After launching Cushion’s new onboarding, I detail the next few items on my to-do list, which for once are not new features.
A weekend turned into a month, but Cushion’s new onboarding is finally live. Instead of focusing on the launch itself, I talk through my favorite part.
To provide a more pleasant codebase for Future Jonnie to inherit, I restructure the onboarding to be composable and easily testable.
I decide to write a few utility methods myself, rather than relying on 3rd party library, and I’m glad I do.
Torn between adding a dependency for a utility method or writing it myself, I talk through the pros and cons of both approaches.
Determined to launch thew onboarding flow, I forgot to write for a week and it shows.
Continuing my work on Cushion’s onboarding flow, I build a new and improved date picker component.
With my recent work on Cushion’s new onboarding flow, I take a meandering walk through the new components I built for it that are all typed and tested.
Stepping back to look at Cushion’s growth over its entire lifetime reveals a crystal clear moment when everything went south.
I start working on the new onboarding flow, but quickly realize it won’t be a weekend project.
As a first stab at onboarding, I design a flow that includes myself asking questions, which hopefully provides a friendly intro to the app.
In an attempt to ease people into the app rather than pushing them out of the airplane, I decide to bring back a proper onboarding flow.
After feeling reluctant to reveal any design progress, I decide to bite the bullet and share a few rough sketches—no matter how uncomfortable it feels.
Continuing the idea of the single click, I talk through a potential path to flattening the nav from multiple layers down to one.
Browsing through Cushion, I realize something strange. As I troubleshoot the anomaly, I discover an embarrassing truth.
I sent my first Cushion newsletter in over a year and a half, which sounds crazy, but nonetheless, it feels great to send them again.
Before diving into analytics, I decide to spend time writing database queries that could validate some of my assumptions using existing data.
After building Cushion so far based purely on assumptions and intuition, I finally start to think about using analytics to help guide me.
A thought-provoking conversation leads me to realize that Cushion is still solid and worth iterating on, instead of restarting from scratch.
After establishing a new guiding principle to keep API requests simple, I describe how I could refactor a complex view that relies on a heavy API request.
While thinking through adding the ability for people to receive posts as emails, I took a detour and reworked the footer area for posts.
Nearing the end of my week off after the Stripe redesign launch, I reflect on what I ended up doing. Long story short, not much, and it was great.
I discuss a pain point in the current Cushion involving the number of clicks it takes to get to where you need to go. What if it only took one?
If you use 100vw and don’t check what your website looks like with scrollbars always visible, it most likely has a horizontal overflow issue.
Almost a decade after my post about using Photoshop’s checkered pattern for loading images, I revisit the code to refactor it for the modern web.
After one week without Twitter and Instagram, I wrote about my experience so far, which has been so beneficial that I wonder if I’ll ever reinstall them.
I feel unhealthy about how I use Twitter and Instagram, scrolling through them only to feel caught up, so I’m deleting both off my phone and taking a break.
While embedding the fixed-size Casper animation on the homepage, I face the technical challenge of gracefully scaling the animation on smaller viewports.
With the goal of improving the UX of the blog’s index, I redesign the layout for easier skimming over the entirety of the blog and better organizing of posts.
Initially about the Stripe section of the homepage, this post quickly diverges into a tirade about frameworks and how vanilla JS is much more future-proof.
After realizing that my articles lead to a dead end after reading, I describe how I added pagination in the form of links to adjacent articles.
This post describes the technical workings of the anchored DT logo, which changes color based on the homepage section being scrolled through.
Once I had enough time to come down after launching the homepage, I write about the concept of embedding all of my scroll-based animations onto one page.
Instead of accompanying the launch of the new homepage with a lengthy process post, I preferred to simply announce the page and enjoy it being out there.
In preparation for the launch of the new redesign, I walk through migrating blog posts from the previous site and flipping the switch to the root domain.
This is a quick post about giving into the centered layout after months of enjoying the classic left-aligned layout.
After realizing the site didn’t include any way of reaching me, I add Twitter and mailto links to the header.
Continuing work on the new Clients section, I revisit client notes, but with a few UX improvements.
Improving a upon the overflow shadows in Cushion, I replace scroll events with the Intersection Observer API.
After rolling out the new Client section to a few dozen beta users, I start applying their feedback.
While making forward progress with the new Clients section, I take a break to upgrade the new codebase to Vue 3.
An already stressful time is made even more stressful by a Safari performance issue with nested grids.
With the Clients section beta up and running, I launch my first incremental update.
A video call with a friend provides some interesting insight into a potential direction for restructuring the app.
After a heads-down week, I managed to reach the first milestone in releasing the new Clients section—private beta.
In an update of the database memory saga, I discover pgbouncer, which puts a stop to the constantly climbing memory woes.
With the sidebar navigation ready to deploy this weekend, I get an early start on the top-level “Clients” section.
After regretting, but living with, the skinny sidebar nav of obscure icons, I finally set a course to improve its UX.
Following up on the initial proof of concept, I build the complete system to send journal posts as emails.
In an effort to grow readership, while also prototyping an idea, I start building a system to email my posts.
Putting the final touches on the invoice form, I apply a sticky behavior to the line item totals.
I spend extra time getting a little detail right by tying shadows to whether the underlying content has overflow.
With the last remaining to-do on my list for the new invoice form, I tackle the flow for importing tracked time.
After realizing standing desks are actually affordable now, I assemble my own using an IKEA countertop.
With the inline forms behind me, I spend a week cleaning up the codebase with a focus on Cushion’s form states.
After detailing how I planned to build inline forms in Cushion, I went ahead and built the first one for creating clients inline.
In between big tasks, I distract myself with smaller tasks until I’m ready to finally face it—inline forms.
Chopping away at the new invoice form, I designed and built a new component for breadcrumbs.
Aggravated by people signing up with no real intention to use Cushion leads me to consider a “test mode” where they can try the app without signing up.
While redesigning the invoice form, I share the decision-making behind the design of the new line item footer.
Frustrated with Heroku, I start migrating away from it, beginning with continuous integration.
Upgrading Cushion’s database leads to a week of troubleshooting performance issues.
After receiving an email from Heroku to upgrade Cushion’s database, I upgrade Cushion’s database.
With Cushion reaching the 7-year mark, I reflect on its life and plot a course for its future.
At the fork in the road, I choose the invoice form as the next step in renovating Cushion, including a long-awaited list of improvements.
With a couple big launches behind me, I think about what to tackle next or whether I need to pick a direction just yet.
After launching Cushion’s new invoice page last week, I launch the new account page this week with a ton of other goodies.