diff options
author | Jean-Nicolas Veigel <art.jnveigel@gmail.com> | 2024-03-14 04:05:51 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2024-03-26 10:31:25 +0000 |
commit | 6b909eea3db887214fdd13dffb1dda48ddc7e420 (patch) | |
tree | aaabc4896d9e331e4ee696ff10e1621ba64d6085 | |
parent | 8c199ac34bd80aeb241412a967d4202cacf5a69b (diff) | |
download | tour-6b909eea3db887214fdd13dffb1dda48ddc7e420.tar.gz tour-6b909eea3db887214fdd13dffb1dda48ddc7e420.zip |
feat: add sugar, links, css & content to /everything page
-rw-r--r-- | src/tour.gleam | 115 | ||||
-rw-r--r-- | static/common.css | 7 | ||||
-rw-r--r-- | static/style.css | 199 |
3 files changed, 270 insertions, 51 deletions
diff --git a/src/tour.gleam b/src/tour.gleam index 707b854..061c191 100644 --- a/src/tour.gleam +++ b/src/tour.gleam @@ -98,7 +98,7 @@ const what_next_html = " const path_home = "/" -const page_contents = "/table-of-contents" +const path_table_of_contents = "/table-of-contents" const path_what_next = "/what-next" @@ -239,7 +239,7 @@ fn write_content(chapters: List(Chapter)) -> snag.Result(Nil) { name: "Table of Contents", text: string.join(list.map(chapters, contents_list_html), "\n"), code: hello_joe, - path: page_contents, + path: path_table_of_contents, previous: None, next: None, )), @@ -519,40 +519,97 @@ fn slugify_path(path: String) -> String { string.replace(path, "/", "") } -fn everything_html(chapters: List(Chapter)) -> String { - let lessons = { - use chapter <- list.flat_map(chapters) - use lesson <- list.flat_map(chapter.lessons) - [ - h("h2", [#("id", slugify_path(lesson.path))], [text(lesson.name)]), +fn separator(class: String) { + h("hr", [#("class", class <> "-separator")], []) +} + +fn everything_chapter_lesson_html(lesson: Lesson, index: Int, end_index: Int) { + let snippet_link_title = "Experiment with " <> lesson.name <> " in browser" + + let lesson_content = + h("article", [#("class", "lesson"), #("id", slugify_path(lesson.path))], [ + h("h2", [#("class", "lesson-title")], [text(lesson.name)]), htmb.dangerous_unescaped_fragment(string_builder.from_string(lesson.text)), - h("pre", [], [h("code", [], [text(lesson.code)])]), - ] + h("pre", [#("class", "lesson-snippet")], [ + h("code", [], [text(lesson.code)]), + h( + "a", + [ + #("class", "lesson-snippet-link"), + #("href", lesson.path), + #("title", snippet_link_title), + #("aria-label", snippet_link_title), + ], + [ + h("i", [#("class", "snippet-link-icon")], [text("</>")]), + text("Run"), + ], + ), + ]), + ]) + + case index { + i if i == end_index -> [lesson_content] + _ -> [lesson_content, separator("lesson")] + } +} + +fn everything_html(chapters: List(Chapter)) -> String { + let chapter_lessons = { + use #(chapter, index) <- list.flat_map( + list.index_map(chapters, fn(chap, i) { #(chap, i) }), + ) + + let end_lesson_index = list.length(chapter.lessons) - 1 + + let chapter_lessons = + chapter.lessons + |> list.index_map(fn(lesson, index) { + everything_chapter_lesson_html(lesson, index, end_lesson_index) + }) + + let chapter_title = + h( + "h3", + [#("id", slugify_path(chapter.path)), #("class", "chapter-title")], + [text(chapter.name)], + ) + + let chapter_header = case index { + 0 -> [chapter_title, separator("chapter")] + _ -> [separator("chapter-between"), chapter_title, separator("chapter")] + } + + list.concat([chapter_header, ..chapter_lessons]) } let table_of_contents = list.map(chapters, fn(chapter) { - h("li", [], [ - h("h3", [], [text(chapter.name)]), - h( - "ul", - [], - list.map(chapter.lessons, fn(lesson) { - h("li", [], [ - h("a", [#("href", "#" <> slugify_path(lesson.path))], [ - text(lesson.name), - ]), - ]) - }), - ), - ]) + h( + "article", + [#("class", "chapter"), #("id", "chapter-" <> chapter.name)], + [ + h("h3", [], [text(chapter.name)]), + h( + "ul", + [], + list.map(chapter.lessons, fn(lesson) { + h("li", [], [ + h("a", [#("href", "#" <> slugify_path(lesson.path))], [ + text(lesson.name), + ]), + ]) + }), + ), + ], + ) }) // TODO: use proper values for location and such - page_html(at: "everything", titled: "Everythingyyy!!!", containing: [ - h("main", [#("class", "everything")], [ - h("ul", [#("class", "everything-contents")], table_of_contents), - h("article", [#("class", "everything-lessons")], lessons), + page_html(at: "everything", titled: "Everything!!!", containing: [ + h("main", [#("id", "everything")], [ + h("aside", [#("id", "everything-contents")], table_of_contents), + h("section", [#("id", "everything-lessons")], chapter_lessons), ]), ]) } @@ -573,7 +630,7 @@ fn lesson_html(page: Lesson) -> String { h("nav", [#("class", "prev-next")], [ navlink("Back", page.previous), text(" — "), - h("a", [#("href", page_contents)], [text("Contents")]), + h("a", [#("href", path_table_of_contents)], [text("Contents")]), text(" — "), navlink("Next", page.next), ]), diff --git a/static/common.css b/static/common.css index 2c9a188..0a73719 100644 --- a/static/common.css +++ b/static/common.css @@ -7,12 +7,13 @@ --aged-plastic-yellow: #fffbe8; --unexpected-aubergine: #584355; --underwater-blue: #292d3e; + --muted-indigo: #303549; --charcoal: #2f2f2f; --black: #1e1e1e; --blacker: #151515; /* Other greys */ - --off-white: #f5f5f5; + --off-white: #f0f0f0; /* Other colors */ --menthol: #c8ffa7; @@ -34,8 +35,8 @@ /* Dark theme */ --dark-theme-background: var(--underwater-blue); - --dark-theme-background-dim: var(--black); + --dark-theme-background-dim: var(--muted-indigo); --dark-theme-text: var(--white); - --dark-theme-text-secondary: var(--aged-plastic-yellow); + --dark-theme-text-secondary: var(--off-white); --dark-theme-code: var(--deep-saffron); } diff --git a/static/style.css b/static/style.css index 396530a..bab9517 100644 --- a/static/style.css +++ b/static/style.css @@ -22,8 +22,11 @@ --font-family-normal: "Outfit", sans-serif; --font-family-title: "Lexend", sans-serif; - --navbar-height: calc(calc(2 * var(--gap)) + 20px); - --gap: 12px; + --gap: 0.75rem; + --gap-double: calc(2 * var(--gap)); + --gap-half: calc(0.5 * var(--gap)); + --gap-quarter: calc(0.25 * var(--gap)); + --navbar-height: calc(var(--gap-double) + 20px); --color-navbar-background: var(--faff-pink); --color-navbar-text: var(--light-theme-text); @@ -34,6 +37,7 @@ html.theme-light { --color-background: var(--light-theme-background); --color-background-dim: var(--light-theme-background-dim); --color-text: var(--light-theme-text); + --color-text-secondary: var(--light-theme-text-secondary); --color-link: var(--light-theme-text); --color-link-decoration: var(--faff-pink); --color-code: var(--light-theme-code); @@ -45,6 +49,7 @@ html.theme-dark { --color-background: var(--dark-theme-background); --color-background-dim: var(--dark-theme-background-dim); --color-text: var(--dark-theme-text); + --color-text-secondary: var(--dark-theme-text-secondary); --color-link: var(--dark-theme-text); --color-link-decoration: var(--faff-pink); --color-code: var(--dark-theme-code); @@ -65,7 +70,6 @@ body { background-color: var(--color-background); font-family: var(--font-family-normal); letter-spacing: 0.01em; - line-height: 1.3; color: var(--color-text); } @@ -76,6 +80,13 @@ code { letter-spacing: initial; } +p { + margin: var(--gap) 0 !important; + font-size: 1rem; + line-height: var(--gap-double); + font-weight: 400; +} + p code { padding: 1px 2px; color: var(--color-code); @@ -97,8 +108,12 @@ h6 { justify-content: space-between; align-items: center; height: var(--navbar-height); + z-index: 100; + position: fixed; + inset: 0; + bottom: unset; padding: var(--gap); - background-color: var(--color-navbar-background); + background: var(--color-navbar-background); color: var(--color-navbar-text); box-shadow: 0 0 5px 5px rgba(0, 0, 0, 0.1); } @@ -381,33 +396,179 @@ html.theme-dark .codeflask .token.attr-value { color: #abb2bf; } -.everything { +/* everything wrapper, 2x2 responsive grid layout */ +main#everything { + display: grid; + max-height: 100vh; + grid-template-columns: minmax(0, max-content) 1fr; + padding-top: var(--navbar-height); + overflow: hidden; +} + +#everything h1, +#everything h2, +#everything h3 { + margin: 0; +} +/* table of contents on the left, scrollable */ +#everything-contents, #everything-lessons { + grid-column-end: span 1; + grid-row: 1 / span 1; padding: var(--gap); + padding-bottom: var(--gap-double); + overflow-y: auto; display: flex; - flex-direction: row-reverse; + background: var(--color-background); + flex-direction: column; } -.everything h2, -.everything h3, -.everything ul { - margin-top: 0; +#everything-contents { + grid-column-start: 1; + background: var(--color-background-dim); + gap: var(--gap-double); } -.everything h3 { - margin-bottom: var(--gap); +#everything-contents * { + margin: 0; } -.everything-contents { - width: 400px; +@media only screen and (min-width: 1100px) { + #everything { + grid-template-columns: minmax(min-content, max-content) 1fr; + } + + #everything-contents { + padding: var(--gap) var(--gap-double) var(--gap-double) var(--gap); + } } -.everything-contents, -.everything-contents ul { +#everything-contents .chapter { + display: flex; + flex-direction: column; + gap: var(--gap); +} + +#everything-contents .chapter h3 { + white-space: nowrap; +} + +#everything-contents .chapter ul, +#everything-contents .chapter li { list-style: none; padding: 0; - margin-bottom: var(--gap); + color: var(--color-text-secondary); +} + +#everything-contents .chapter ul { + display: flex; + flex-direction: column; + gap: var(--gap-half); +} + +#everything-contents a { + color: var(--color-text-secondary); + transition: color 150ms ease-out 0s; +} + +#everything-contents a:hover { + color: var(--color-link); +} + +#everything-lessons { + grid-column-start: 2; + gap: var(--gap-quarter); + container-type: inline-size; + container-name: lessons-list; +} + + +#everything-lessons .chapter-title { + margin: 0; + margin-top: var(--gap); + color: var(--faff-pink); +} + +#everything-lessons .chapter-title:first-child { + margin-top: 0; +} + +#everything-lessons .lesson { + margin: var(--gap) 0; + padding: var(--gap) 0; +} + +#everything-lessons .lesson * { + margin: 0; +} + +#everything-lessons .lesson-snippet { + padding: var(--gap) var(--gap-half); + margin-top: var(--gap-double); + background: var(--color-background-dim); + position: relative; +} + +#everything-lessons .lesson-snippet-link { + background: var(--color-background); + position: absolute; + top: var(--gap-half); + right: var(--gap-half); + padding: var(--gap-half); + display: flex; + align-items: center; + justify-content: center; + gap: var(--gap); + font-size: 0.75rem; + line-height: 0.75rem; + color: var(--color-link); + border-radius: none; + text-decoration: none; + outline: 1px solid transparent; + outline-offset: -1px; + cursor: pointer; + transition: all 300ms ease-out 0s; +} + +#everything-lessons .lesson-snippet-link:hover { + color: var(--color-background); + background: var(--color-link); + transition: all 120ms ease-in 0s; + outline-color: var(--faff-pink); +} + +#everything-lessons .snippet-link-icon { + color: var(--faff-pink); + font-weight: bold; + text-decoration: none !important; +} + +#everything-lessons hr { + width: 100%; + height: 1px; + border: 0; + padding: 0; + margin: 0; + display: block; +} + +#everything-lessons .lesson-separator { + border-top: 1px solid var(--color-background-dim); } -.everything-contents li li { - padding-left: var(--gap); +#everything-lessons .chapter-separator { + border-top: 1px solid var(--faff-pink); } + +@container lessons-list (min-width: 900px) { + #everything-lessons .lesson, + #everything-lessons .chapter-title { + padding-right: var(--gap-double); + padding-left: var(--gap-double); + } + + #everything-lessons .chapter-separator { + margin-left: var(--gap-double); + width: calc(100% - var(--gap-double)); + } + +}
\ No newline at end of file |