aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Nicolas Veigel <art.jnveigel@gmail.com>2024-03-14 04:05:51 +0100
committerLouis Pilfold <louis@lpil.uk>2024-03-26 10:31:25 +0000
commit6b909eea3db887214fdd13dffb1dda48ddc7e420 (patch)
treeaaabc4896d9e331e4ee696ff10e1621ba64d6085
parent8c199ac34bd80aeb241412a967d4202cacf5a69b (diff)
downloadtour-6b909eea3db887214fdd13dffb1dda48ddc7e420.tar.gz
tour-6b909eea3db887214fdd13dffb1dda48ddc7e420.zip
feat: add sugar, links, css & content to /everything page
-rw-r--r--src/tour.gleam115
-rw-r--r--static/common.css7
-rw-r--r--static/style.css199
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