diff options
Diffstat (limited to 'src/tour.gleam')
-rw-r--r-- | src/tour.gleam | 81 |
1 files changed, 80 insertions, 1 deletions
diff --git a/src/tour.gleam b/src/tour.gleam index 17386c9..fe163ae 100644 --- a/src/tour.gleam +++ b/src/tour.gleam @@ -8,6 +8,7 @@ import gleam/result import simplifile import filepath import snag +import icons const static = "static" @@ -516,7 +517,7 @@ fn lesson_html(page: Lesson) -> String { let description = "An interactive introduction and reference to the Gleam programming language. Learn Gleam in your browser!" - h("html", [#("lang", "en-gb")], [ + h("html", [#("lang", "en-gb"), #("class", "theme-light")], [ h("head", [], [ h("meta", [#("charset", "utf-8")], []), h( @@ -540,6 +541,7 @@ fn lesson_html(page: Lesson) -> String { metaprop("twitter:description", description), metaprop("twitter:image", "https://gleam.run/images/og-image.png"), link("shortcut icon", "https://gleam.run/images/lucy/lucy.svg"), + link("stylesheet", "/common.css"), link("stylesheet", "/style.css"), h( "script", @@ -550,6 +552,11 @@ fn lesson_html(page: Lesson) -> String { ], [], ), + h("script", [#("type", "module")], [ + htmb.dangerous_unescaped_fragment(string_builder.from_string( + theme_picker_js, + )), + ]), ]), h("body", [], [ h("nav", [#("class", "navbar")], [ @@ -564,6 +571,32 @@ fn lesson_html(page: Lesson) -> String { ), text("Gleam Language Tour"), ]), + h("div", [#("class", "nav-right")], [ + h("div", [#("class", "theme-picker")], [ + h( + "button", + [ + #("type", "button"), + #("alt", "Switch to light mode"), + #("title", "Switch to light mode"), + #("class", "theme-button -light"), + #("data-light-theme-toggle", ""), + ], + [icons.icon_moon(), icons.icon_toggle_left()], + ), + h( + "button", + [ + #("type", "button"), + #("alt", "Switch to dark mode"), + #("title", "Switch to dark mode"), + #("class", "theme-button -dark"), + #("data-dark-theme-toggle", ""), + ], + [icons.icon_sun(), icons.icon_toggle_right()], + ), + ]), + ]), ]), h("article", [#("id", "playground")], [ h("section", [#("id", "left")], [ @@ -595,3 +628,49 @@ fn lesson_html(page: Lesson) -> String { |> htmb.render_page("html") |> string_builder.to_string } + +// This script is inlined in the response to avoid FOUC when applying the theme +const theme_picker_js = " +const mediaPrefersDarkTheme = window.matchMedia('(prefers-color-scheme: dark)') + +function selectTheme(selectedTheme) { + // Apply and remember the specified theme. + applyTheme(selectedTheme) + if ((selectedTheme === 'dark') === mediaPrefersDarkTheme.matches) { + // Selected theme is the same as the device's preferred theme, so we can forget this setting. + localStorage.removeItem('theme') + } else { + // Remember the selected theme to apply it on the next visit + localStorage.setItem('theme', selectedTheme) + } +} + +function applyTheme(theme) { + document.documentElement.classList.toggle('theme-dark', theme === 'dark') + document.documentElement.classList.toggle('theme-light', theme !== 'dark') +} + +// If user had selected a theme, load it. Otherwise, use device's preferred theme +const selectedTheme = localStorage.getItem('theme') +if (selectedTheme) { + applyTheme(selectedTheme) +} else { + applyTheme(mediaPrefersDarkTheme.matches ? 'dark' : 'light') +} + +// Watch the device's preferred theme and update theme if user did not select a theme +mediaPrefersDarkTheme.addEventListener('change', () => { + const selectedTheme = localStorage.getItem('theme') + if (!selectedTheme) { + applyTheme(mediaPrefersDarkTheme.matches ? 'dark' : 'light') + } +}) + +// Add handlers for theme selection buttons. +document.querySelector('[data-light-theme-toggle]').addEventListener('click', () => { + selectTheme('light') +}) +document.querySelector('[data-dark-theme-toggle]').addEventListener('click', () => { + selectTheme('dark') +}) +" |