Tutorial Explorer is the standalone React app that delivers the functionality of https://code.org/learn and https://hourofcode.com/learn, the pages commonly known as "slash learn". It was built for the fourth annual Hour of Code in 2016, providing the official catalogue of both first- and third-party Hour of Code tutorials in an explorable and filterable interface, and has been used ever since.
At the time of writing, the pages have over 190 million pageviews, with over 130 million of them unique.
The host page is responsible for providing the header banner, and then embeds the React app.
The app itself provides a grid of tiles, one for each tutorial. The tile images are lazy-loaded as they are near to being scrolled into view. Each tile can be clicked to show a popup with additional metadata and a link to launch the tutorial in a new browser tab. The left/right arrow keys can be used to go forward/back while the popup is showing.
Above and beside the tiles are a variety of filters to help refine the set of tutorials being shown. The filters include grade range, student experience, creator, platform, subject, activity type, length, and programming language.
It's also possible to change the sort order, either by "Most popular" or "Recommended". See the discussion below about Variables for information on the default sort order.
On particuarly narrow screens, the filters are no longer shown at the same time as the tiles. Instead, only tiles are shown at first, and the filters can be toggled to show in their place with a "Filters" button, or dismissed with an "Apply" button. We show the actual count of filtered tutorials in this situation, mainly because the changing set of tutorials isn't visible when only the filters are showing; the count helps indicate when changing a filter is making a difference.
When visiting the page in a non-en language, it first shows a set of tiles for "Activities in your language", that is tutorials that we know have explicit support for that language. Below this set of tiles is a button which, when pressed, reveals the larger set of tutorials and filter options.
The UI renders a layout that varies with different browser window widths. A simple new system was introduced here, and is inspired by Bootstrap, which we were using in other parts of our site at the time.
There are a few functions provided. Here is how one of them can be used:
width: getResponsiveValue({lg: 33.3333333, sm: 50, xs: 100})
Depending upon the current browser width, and whether that's considered "large", "small", or "extra-small", a different width can be applied to a given element. (And in the case of the browser being at "medium", the function falls down to use the "small" value, since a "medium" one isn't provided.)
At the core of the app is a filtering algorithm, implemented in the filterTutorials function. The comments describe its behavior with some detail. Its role is to translate the user's choices in the user interface to an appropriate subset of the entire tutorial set.
Care was taken to unit test this functionality.
The page's source HTML initializes the Tutorial Explorer in JavaScript with a parameter containing all of the tutorial metadata. That page is rendered by Pegasus, and the tutorial metadata comes from an in-house gsheet which is used to generate cdo-tutorials.csv which is ingested daily into our source tree and used to seed the Pegasus database in each environment, alongside a variety of other gsheets' data.
Management of the source gsheet is a significant task in itself, and the sheet has some internal complexity so that it can generate the appropriate values for the variety of displayweight_* and popularityrank_* columns (which correspond to "Recommended" vs. "Most popular" in the UI).
Each React component is in its own file with a brief comment at the top describing its use.
Here are some notable components, and their hierarchy:
TutorialExplorerFilterHeader: the set of filters at the topFilterGroupHeaderSelection: used for two filters
FilterSet: the set of filters on the left sideFilterGroupSortBy: the "Sort by" dropdownFilterGroupOrgNames: the "Organization" dropdownFilterGroup: a variety of filter groupsFilterChoice: a variety of filter options with checkboxes
TutorialSet: the tutorial tilesTutorial: an individual tileTutorialDetail: a popup with information about a tutorial
ToggleAllTutorialsButton: a button to toggle showing all tutorials, for non-English users
Three DCDO variables can be used to vary the behaviour of the Tutorial Explorer without requiring a deploy to the site:
learn_show_sort_dropdown: Whether the "Sort by" dropdown should be shown at all. Defaults totrue.learn_hide_tutorials: An array of tutorial "short codes" that should be hidden. Useful if a tutorial suddenly becomes unavailable, say due to a server issue. Defaults to[].defaultSortByPopularity: Whether the "Sort by" option defaults to sorting by "Most popular", rather than "Recommended". The default here actually varies by site and currenthoc_mode, with the logic captured here.
When a tutorial is started, we open it in a new browser tab. Since the Tutorial Explorer tab remains in existence, we simply generate a couple Google Analytics events at the same time, as seen here.
There is some rudimentary detection for mobile devices. If a mobile device is successfully detected, the Android & iOS options are initially checked.
It is possible to pass a custom URL to /learn to pre-select the filters shown.
Here's a simple example:
https://hourofcode.com/learn?platform=no-computers
This says that for filter platform, entry no-computers should be selected.
It's also possible to specify multiple filter entries, even for the same filter, for example:
https://hourofcode.com/learn?grade=pre&grade=2-5&platform=no-computers
Here is a full list of the filter names & entries that can be specified:
grade: pre, 2-5, 6-8, 9+
teacher_experience: beginner, comfortable
student_experience: beginner, comfortable
platform: computers, android, ios, no-internet, no-computers
subject: science, math, history, la, art, cs-only
activity_type: online-tutorial, lesson-plan
length: 1hour, 1hour-follow, few-hours
programming_language: blocks, typing, other
Important note: In order to ensure satisfactory web performance, list these parameters in the order of the above list. (This will allow each variant to be cached as one.)
For example, do not specify: https://hourofcode.com/learn?subject=science&platform=computers
Instead, specify: https://hourofcode.com/learn?platform=computers&subject=science
