Skip to content

Instantly share code, notes, and snippets.

@busypeoples
Last active March 1, 2024 01:03
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save busypeoples/921bf703bdd1d972c2016afcb9401030 to your computer and use it in GitHub Desktop.
Save busypeoples/921bf703bdd1d972c2016afcb9401030 to your computer and use it in GitHub Desktop.

Notes on Modern UI Development: Iterating over the other 80%

Introduction

I have been working on a modern typing training application for the last couple of days. One of the main motivations was to build an app with a modern UI and minimal distractions, enabling to fully focus on the training aspect. You can read more about the original idea and thought process here.

One of the main features is being able to train your typing speed when working with code, which means the typing experience should come close to how you would type when working with an IDE. A feature that you would normally get inside such an environment is the auto closing of parentheses, brackets and braces. Which means you would for example type ( and the IDE would automatically add the closing ) for you.

The first iteration of Typing Cyclist was just a raw implementation which treated text and code examples the same. You would have to type out the text or code character by character. While this makes sense when training with text examples, it's less then optimal when it comes to the code eqivalent.

This was the state of things when training with code:

Typing Cyclist Code Mode Example

Challenges and Implementation

Thinking about how to bring an IDE like experience to a type training app is an interesting challenge due to the fact that everyone types out there code differently. To get a better understanding of the challenge, let's look at a basic TypeScript example:

function multiplyBy(x: number) {
  const arr = [1, 2, 3, 4, 5, 6];
  return arr.map((n) => n * x);
}

How would you type out the code inside an IDE?

Most probably the following would happen: you would type function multiplyBy( and the IDE would auto close with ) while the cursor would be automatically positioned between ( and ).

But what happens when we press backspace? Our code might look like this: function multiplyBy - with both, the opening and closing elements removed.

Short example showing how to type out code with an opening ( and closing )

What happens when you move the cursor forward and then backwards and then press backspace? We get function multiplyBy) with the IDE most probably highlighting the fact, that the code is invalid. The interesting part is that the inserted ) remains, although we removed the original opening (.

Short example showing how to type out code with an opening ( and closing )

Now let's go back to our starting scenario, the cursor is still positioned between ( and ) and we type ], now we should have the following outcome: function multiplyBy(]) again our IDE will most probably complain by highlighting the broken code. But if we type ) instead, it would re-apply the ) and we would have valid code: function multiplyBy() not function multiplyBy()).

Short example showing how to type out code with an opening ( and closing )

So far all the examples can be solved inside the training app because they operate on the same line, but what happens when we have to deal with an auto complete that spans multiple lines. If we take the original example, we encounter an opening { on the first line but the closing } is on line 4. This scenario is more complicated because we would most probably type it like the following first:

function multiplyBy(x: number) {}

and while the cursor is placed between { and }, we might then type out the body part of the function. This is an interesting challenge for our type training app. We already have the complete function on the screen and the typist has to follow along and type the representation character for character. So how can we make this scenario more realistic?

One possible approach is to hide the body part of the function until you reach the { and the app auto completes the }, positioning the cursor between the two and then making the function body appear. But this seems very confusing from a user perspective.

The other idea is to always show the complete code and for a short moment, hide the function body when typing { and auto closing it with } and then bring the code back in. See how this works:

Typing App demo showing how auto closing is handled

This is how it is implemented in Typing Cyclist right now. We hide and show the code when needed.

Summary

It's interesting how with think about the UI and they way it should work sometimes. We might overestimate how long building out a basic feature is but underestimate the little details and how complicated things can become when iterating over these details. So it can be 80% for the basic functionality and another 80% for getting the details right.

The Typing Cyclist demo is here: https://typing-cyclist.vercel.app

You can checkout the code example demo here: https://typing-cyclist.vercel.app/code/?courseId=1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment