From a8410df42aaf27c747b5db98655d1542c70cc2f9 Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Thu, 15 Jan 2026 11:52:26 +0100 Subject: [PATCH] feat: improve section pages with GitBook-style layout and landing page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add side-by-side layout for section pages (text left, code right) - Include educational content with code examples for CSS, HTML, Tailwind - Add section overviews explaining each technology - Make header level pill clickable to return to last lesson - Update landing page with "How It Works" steps and features section - Improve code block readability with GitHub-dark color scheme - Add prominent topic links with SEO-friendly accessible text - Add responsive grid layout that stacks on mobile 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- src/app.js | 386 ++++++++++++++++++++++++++++++++++++++++++++----- src/index.html | 76 ++++++++-- src/main.css | 289 ++++++++++++++++++++++++++++++++++++ 3 files changed, 702 insertions(+), 49 deletions(-) diff --git a/src/app.js b/src/app.js index 5e884e4..1c54a89 100644 --- a/src/app.js +++ b/src/app.js @@ -35,7 +35,7 @@ const elements = { sectionDescription: document.getElementById("section-description"), sectionProgressFill: document.getElementById("section-progress-fill"), sectionProgressText: document.getElementById("section-progress-text"), - moduleGrid: document.getElementById("module-grid"), + sectionIntro: document.getElementById("section-intro"), // Left panel instructionsSection: document.querySelector(".instructions"), @@ -510,10 +510,11 @@ function loadCurrentLesson() { // Update level indicator renderLevelIndicator(elements.levelIndicator, engineState.lessonIndex + 1, engineState.totalLessons); - // Header pill shows module name + level + // Header pill shows module name + level (clickable link to return to lesson) if (elements.headerLevelPill && engineState.module) { const label = t("lessonLabel"); elements.headerLevelPill.innerHTML = `${engineState.module.title} ${label} ${engineState.lessonIndex + 1} / ${engineState.totalLessons}`; + elements.headerLevelPill.href = `#${engineState.module.id}/${engineState.lessonIndex}`; } // Update active lesson in sidebar @@ -819,6 +820,347 @@ async function copyShareUrl() { } } +// ================= SECTION EDUCATIONAL CONTENT ================= + +const sectionContent = { + css: ` +
+

CSS (Cascading Style Sheets) is a stylesheet language that controls the visual presentation of HTML documents. While HTML defines the structure and content, CSS handles colors, typography, spacing, and layout. The "cascading" in CSS means rules can override each other based on specificity—allowing you to set defaults and then refine them for specific elements.

+

Introduced in 1996 to separate content from presentation, CSS enables one stylesheet to style multiple HTML pages, keeping design consistent and maintainable. Modern CSS includes powerful layout systems like Flexbox and Grid, custom properties (variables), and animations—all without JavaScript.

+
+ +
+
+

Selectors & Properties

+

CSS uses selectors to target HTML elements and apply styles. The most common selector is the class selector (.classname), which targets elements with a specific class attribute. You can also use element selectors (p, div), ID selectors (#id), and combinators to select nested elements.

+

Properties define what aspect of the element to style. Common properties include color for text color, background for backgrounds, padding for internal spacing, and margin for external spacing. Each property accepts specific value types like colors, lengths, or keywords.

+ Practice CSS Selectors +
+
+
+
.button {
+  background: steelblue;
+  color: white;
+  padding: 0.5rem 1rem;
+  border-radius: 4px;
+}
+
+.button:hover {
+  background: darkslateblue;
+}
+
+
+
+ +
+
+

The Box Model

+

Every HTML element is rendered as a rectangular box with four distinct layers. The content area holds your text or images. padding creates space inside the element between the content and border. The border wraps around the padding. Finally, margin creates space outside the element, separating it from neighbors.

+

By default, width only sets the content width. Adding padding and border increases the total size. Use box-sizing: border-box to include padding and border in the declared width, making layouts much more predictable.

+ Learn the CSS Box Model +
+
+
+
.card {
+  width: 300px;
+  padding: 1rem;
+  border: 2px solid gray;
+  margin: 1rem;
+  box-sizing: border-box;
+}
+/* Total width stays 300px */
+
+
+
+ +
+
+

Flexbox Layout

+

Flexbox is a one-dimensional layout system for arranging items in rows or columns. Apply display: flex to a container to enable it. Child elements become flex items that can grow, shrink, and align automatically.

+

Control alignment with justify-content (main axis: flex-start, center, space-between) and align-items (cross axis: stretch, center, flex-end). The gap property adds consistent spacing between items without margins.

+ Master CSS Flexbox Layout +
+
+
+
.navbar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  gap: 1rem;
+}
+
+.nav-links {
+  display: flex;
+  gap: 2rem;
+}
+
+
+
+ +
+
+

CSS Grid

+

CSS Grid is a two-dimensional layout system for creating complex row and column layouts. Enable it with display: grid, then define columns using grid-template-columns. The repeat() function creates multiple tracks, and fr units distribute available space proportionally.

+

Grid excels at page layouts and card grids. Use grid-template-columns: repeat(3, 1fr) for three equal columns, or repeat(auto-fill, minmax(250px, 1fr)) for responsive columns that wrap automatically.

+ Explore CSS Grid Layout +
+
+
+
.gallery {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 1rem;
+}
+
+.responsive-grid {
+  grid-template-columns:
+    repeat(auto-fill, minmax(250px, 1fr));
+}
+
+
+
+ +
+
+

Units & Variables

+

CSS supports multiple unit types for different use cases. Use px for fixed sizes, rem for scalable typography (relative to root font size), % for parent-relative sizing, and vh/vw for viewport-relative dimensions. Prefer rem for accessibility—it respects user font preferences.

+

CSS custom properties (variables) store reusable values. Define them with --name: value in :root for global access, then use them anywhere with var(--name). This makes themes and consistent design systems easy to maintain.

+ Study CSS Units & Variables +
+
+
+
:root {
+  --primary: steelblue;
+  --spacing-sm: 0.5rem;
+  --spacing-md: 1rem;
+  --radius: 8px;
+}
+
+.card {
+  background: var(--primary);
+  padding: var(--spacing-md);
+  border-radius: var(--radius);
+}
+
+
+
+ `, + + html: ` +
+

HTML (HyperText Markup Language) is not a programming language—it's a markup language that describes the structure and content of web documents. Invented by Tim Berners-Lee in 1989, HTML uses tags like <p>, <h1>, and <a> to define paragraphs, headings, and links. The browser reads this markup and renders it as a visual page.

+

HTML documents form a hierarchical tree called the DOM (Document Object Model). Elements have parent-child relationships: a <ul> contains <li> children, a <form> contains <input> elements. Modern HTML5 includes native interactive elements like <dialog>, <details>, and form validation—features that previously required JavaScript.

+
+ +
+
+

Semantic Structure

+

HTML5 introduced semantic elements that convey meaning about content structure. Use <header> for introductory content, <nav> for navigation links, <main> for primary content, <article> for self-contained compositions, <section> for thematic groupings, and <footer> for closing content.

+

Semantic markup improves accessibility—screen readers announce element roles. It also helps SEO as search engines better understand your content hierarchy. Replace generic <div> containers with appropriate semantic elements whenever possible.

+ Learn HTML Semantic Elements +
+
+
+
<article>
+  <header>
+    <h1>Article Title</h1>
+    <time datetime="2024-01-15">
+      January 15, 2024
+    </time>
+  </header>
+  <p>Article content...</p>
+  <footer>
+    <p>Written by Author</p>
+  </footer>
+</article>
+
+
+
+ +
+
+

Forms & Validation

+

HTML forms collect user input with elements like <input>, <select>, <textarea>, and <button>. Always pair inputs with <label> elements using matching for and id attributes—this is crucial for accessibility and usability.

+

Native validation attributes eliminate JavaScript for common cases: required prevents empty submissions, type="email" validates email format, minlength/maxlength control text length, and pattern accepts custom regex patterns. The browser handles error messages automatically.

+ Build HTML Forms +
+
+
+
<form>
+  <label for="email">Email</label>
+  <input type="email" id="email"
+         name="email" required
+         placeholder="you@example.com">
+
+  <label for="phone">Phone</label>
+  <input type="tel" id="phone"
+         pattern="[0-9]{3}-[0-9]{4}">
+
+  <button type="submit">Send</button>
+</form>
+
+
+
+ +
+
+

Interactive Elements

+

Modern HTML includes powerful interactive components that work without JavaScript. The <details> element creates native accordions—click <summary> to toggle visibility. Add the open attribute to start expanded. Multiple details elements create FAQ-style interfaces instantly.

+

The <dialog> element creates accessible modal dialogs. Call .showModal() in JavaScript to open it with backdrop and focus trapping built-in. Use <datalist> with inputs to provide autocomplete suggestions from a predefined list.

+ Try Interactive HTML Elements +
+
+
+
<details>
+  <summary>What is HTML?</summary>
+  <p>HTML is the standard markup
+     language for web pages.</p>
+</details>
+
+<dialog id="confirm">
+  <h2>Confirm Action</h2>
+  <p>Are you sure?</p>
+  <button onclick="this.closest('dialog').close()">
+    Close
+  </button>
+</dialog>
+
+
+
+ +
+
+

Tables & Lists

+

Use <table> exclusively for tabular data, never for page layout. Structure tables with <thead> for header rows, <tbody> for data rows, and optionally <tfoot> for summaries. Mark header cells with <th> (not <td>) and add scope="col" or scope="row" for accessibility.

+

Lists come in three flavors: <ul> for unordered bullet lists, <ol> for numbered sequences, and <dl> for definition lists (term/description pairs). Nest lists for hierarchical content like navigation menus or category trees.

+ Structure Data with HTML Tables +
+
+
+
<table>
+  <thead>
+    <tr>
+      <th scope="col">Product</th>
+      <th scope="col">Price</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td>Widget</td>
+      <td>$9.99</td>
+    </tr>
+  </tbody>
+</table>
+
+
+
+ `, + + tailwind: ` +
+

Tailwind CSS is a utility-first CSS framework that takes a radically different approach to styling. Instead of writing custom CSS classes like .card or .button, you compose designs using small, single-purpose utility classes directly in your HTML: class="p-4 bg-white rounded shadow".

+

This approach solves common CSS problems: no more specificity battles, no unused styles, no inventing class names. Tailwind's consistent spacing scale (p-1 through p-12), color palette (blue-500, gray-100), and responsive prefixes (md:, lg:) make building consistent, responsive interfaces fast and predictable.

+
+ +
+
+

Utility-First Basics

+

Tailwind CSS uses small, single-purpose utility classes applied directly in HTML. Instead of writing .btn { background: blue; padding: 1rem; } in a stylesheet, you write class="bg-blue-500 p-4" on the element. Each class does exactly one thing, making styles predictable and composable.

+

This approach eliminates context-switching between HTML and CSS files. Common utilities include text-lg for font size, font-bold for weight, rounded for border radius, and shadow for box shadows. Hover states use the hover: prefix like hover:bg-blue-600.

+ Start with Tailwind CSS Basics +
+
+
+
<button class="bg-blue-500 text-white
+               px-4 py-2 rounded-lg
+               font-semibold shadow
+               hover:bg-blue-600
+               active:bg-blue-700">
+  Click me
+</button>
+
+
+
+ +
+
+

Spacing & Sizing

+

Tailwind's spacing scale is consistent and memorable. The pattern is simple: p-4 means padding of 1rem (16px), p-2 is 0.5rem, p-8 is 2rem. The same numbers work for margin (m-4), gap (gap-4), and space utilities. Use directional variants like px-4 (horizontal) or pt-2 (top only).

+

Width and height follow patterns too: w-full for 100%, w-1/2 for 50%, w-64 for fixed 16rem, h-screen for viewport height. Combine max-w-xl with mx-auto for centered containers with maximum widths.

+ Learn Tailwind Spacing & Sizing +
+
+
+
<div class="max-w-xl mx-auto p-6">
+  <div class="space-y-4">
+    <div class="w-full h-32 bg-gray-200
+                rounded-lg">
+      Full width card
+    </div>
+    <div class="w-1/2 p-4 bg-gray-100">
+      Half width, padded
+    </div>
+  </div>
+</div>
+
+
+
+ +
+
+

Flexbox & Grid

+

Tailwind's layout utilities map directly to CSS flexbox and grid. Enable flex with flex, then control direction (flex-row, flex-col), alignment (items-center, justify-between), and wrapping (flex-wrap). The gap-4 utility adds consistent spacing between items.

+

For grid layouts, use grid with column definitions like grid-cols-3 for three equal columns or grid-cols-[200px_1fr] for custom track sizes. The col-span-2 utility makes items span multiple columns.

+ Build Layouts with Tailwind +
+
+
+
<nav class="flex justify-between
+            items-center p-4">
+  <a href="/" class="font-bold">Logo</a>
+  <ul class="flex gap-6">
+    <li>Home</li>
+    <li>About</li>
+  </ul>
+</nav>
+
+<div class="grid grid-cols-3 gap-4">
+  <div class="col-span-2">Wide</div>
+  <div>Normal</div>
+</div>
+
+
+
+ +
+
+

Responsive Design

+

Tailwind uses mobile-first responsive prefixes. Unprefixed utilities apply to all screen sizes. Add sm: (640px+), md: (768px+), lg: (1024px+), or xl: (1280px+) prefixes to apply styles at specific breakpoints and above.

+

Build responsive layouts by starting with mobile styles, then adding larger-screen overrides. For example, flex-col md:flex-row stacks items vertically on mobile and horizontally on medium screens. Use hidden md:block to show/hide elements at different sizes.

+ Tailwind Responsive Design +
+
+
+
<div class="flex flex-col md:flex-row
+            gap-4 p-4">
+  <aside class="w-full md:w-64
+               bg-gray-100 p-4">
+    Sidebar (top on mobile)
+  </aside>
+  <main class="flex-1">
+    Main content
+  </main>
+</div>
+
+<p class="text-sm md:text-base lg:text-lg">
+  Responsive typography
+</p>
+
+
+
+ ` +}; + // ================= URL ROUTING & PAGE SWITCHING ================= function initRouter() { @@ -927,7 +1269,12 @@ function showSectionPage(sectionId) { if (elements.sectionTitle) elements.sectionTitle.textContent = section.title; if (elements.sectionDescription) elements.sectionDescription.textContent = section.description; - // Get modules for this section + // Inject educational content (includes integrated module links) + if (elements.sectionIntro && sectionContent[sectionId]) { + elements.sectionIntro.innerHTML = sectionContent[sectionId]; + } + + // Get modules for this section to calculate progress const sectionModules = getModulesBySection(lessonEngine.modules, sectionId); // Calculate section progress @@ -945,39 +1292,6 @@ function showSectionPage(sectionId) { const percent = total > 0 ? Math.round((completed / total) * 100) : 0; if (elements.sectionProgressFill) elements.sectionProgressFill.style.width = `${percent}%`; if (elements.sectionProgressText) elements.sectionProgressText.textContent = `${completed} of ${total} lessons complete`; - - // Render module cards - renderModuleGrid(sectionModules, sectionId); -} - -/** - * Render module cards in section page - */ -function renderModuleGrid(modules, sectionId) { - if (!elements.moduleGrid) return; - - elements.moduleGrid.innerHTML = ""; - - modules.forEach((module) => { - const card = document.createElement("a"); - card.href = `#${module.id}/0`; - card.className = "module-card"; - - // Calculate module progress - const progress = lessonEngine.userProgress[module.id]; - const completed = progress?.completed?.length || 0; - const total = module.lessons.length; - - card.innerHTML = ` -

${module.title}

-
- ${total} lessons - ${completed > 0 ? `${completed}/${total}` : ""} -
- `; - - elements.moduleGrid.appendChild(card); - }); } /** diff --git a/src/index.html b/src/index.html index a0ce040..365d592 100644 --- a/src/index.html +++ b/src/index.html @@ -19,7 +19,7 @@ - + + +
+

How It Works

+
+
+ 1 +

Write Code

+

+ Type CSS, HTML, or Tailwind directly in the browser editor. No installation, no configuration—start coding + immediately. +

+
+
+ 2 +

See Results

+

Watch your changes appear instantly in the live preview. Understand how each property affects the output.

+
+
+ 3 +

Build Skills

+

Complete focused exercises that reinforce concepts. Track your progress and return anytime to continue.

+
+
+
+ +
+
+
+

Beginner Friendly

+

+ No prior experience required. Lessons start with fundamentals and introduce concepts gradually, with clear + explanations for each step. +

+
+
+

Practical Focus

+

+ Every exercise teaches skills you'll use in real projects—flexbox layouts, form styling, responsive design, and + modern CSS techniques. +

+
+
+
+ +
+ Start Learning +

Free and open source. No account required.

+
diff --git a/src/main.css b/src/main.css index c353f47..51c3c97 100644 --- a/src/main.css +++ b/src/main.css @@ -149,6 +149,15 @@ kbd { color: var(--text-muted); white-space: nowrap; margin-left: var(--spacing-sm); + text-decoration: none; + transition: + background 0.2s, + color 0.2s; +} + +.header-level-pill:hover { + background: var(--primary-bg-medium); + color: var(--primary-color); } .header-module-name { @@ -1618,6 +1627,120 @@ input:checked + .toggle-slider::before { font-weight: 500; } +/* Landing About Section */ +.landing-about { + padding: 3rem 1rem; + text-align: center; +} + +.landing-about h2 { + font-size: 1.75rem; + color: var(--primary-dark); + margin-bottom: 2rem; +} + +.about-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 2rem; + text-align: left; +} + +.about-item { + text-align: center; +} + +.about-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2.5rem; + height: 2.5rem; + background: var(--primary-color); + color: white; + font-weight: 700; + font-size: 1.1rem; + border-radius: 50%; + margin-bottom: 1rem; +} + +.about-item h3 { + font-size: 1rem; + color: var(--primary-dark); + margin-bottom: 0.5rem; +} + +.about-item p { + color: var(--light-text); + line-height: 1.6; +} + +/* Landing Features */ +.landing-features { + padding: 2rem 1rem; + max-width: 800px; + margin: 0 auto; +} + +.feature-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 3rem; +} + +.feature-text h3 { + font-size: 1rem; + color: var(--primary-dark); + margin-bottom: 0.5rem; +} + +.feature-text p { + color: var(--light-text); + line-height: 1.6; + font-size: 0.95rem; +} + +@media (max-width: 600px) { + .feature-row { + grid-template-columns: 1fr; + gap: 1.5rem; + } +} + +/* Landing CTA */ +.landing-cta { + text-align: center; + padding: 2rem 1rem 3rem; +} + +.cta-button { + display: inline-block; + padding: 1rem 2.5rem; + background: var(--primary-color); + color: white; + text-decoration: none; + border-radius: var(--border-radius-md); + font-weight: 600; + font-size: 1.1rem; + transition: + background 0.2s, + transform 0.2s, + box-shadow 0.2s; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); +} + +.cta-button:hover { + background: var(--primary-dark); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +.cta-sub { + color: var(--light-text); + font-size: 0.875rem; + margin-top: 1rem; +} + /* ================= SECTION PAGE ================= */ .section-page { flex: 1; @@ -1654,6 +1777,172 @@ input:checked + .toggle-slider::before { margin-bottom: var(--spacing-xs); } +.section-content { + max-width: 1200px; + margin: 0 auto; +} + +/* Section Intro - Educational Content (GitBook-style side-by-side) */ +.section-intro { + padding: 0 var(--spacing-md); +} + +/* Section Overview - intro paragraph */ +.section-overview { + padding: 1.5rem 0 2rem; + border-bottom: 1px solid var(--border-color); + margin-bottom: 0.5rem; +} + +.section-overview p { + color: var(--text-color); + line-height: 1.7; + margin-bottom: 1rem; + max-width: 85ch; +} + +.section-overview p:last-child { + margin-bottom: 0; +} + +.section-overview strong { + color: var(--primary-dark); +} + +.section-overview code { + background: var(--primary-bg-light); + color: var(--primary-dark); + padding: 0.1rem 0.35rem; + border-radius: 4px; + font-family: "JetBrains Mono", "Fira Code", Consolas, monospace; + font-size: 0.85em; +} + +/* Topic Row - side by side layout */ +.topic-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 2rem; + padding: 2rem 0; + border-bottom: 1px solid var(--border-color); + align-items: start; +} + +.topic-row:last-child { + border-bottom: none; +} + +.topic-text h2 { + font-size: 1.25rem; + color: var(--primary-dark); + margin: 0 0 0.75rem; +} + +.topic-text h3 { + font-size: 1rem; + color: var(--primary-dark); + margin: 0 0 0.5rem; +} + +.topic-text p { + color: var(--text-color); + line-height: 1.6; + margin: 0 0 1rem; +} + +.topic-text p:last-child { + margin-bottom: 0; +} + +.topic-link { + display: inline-flex; + align-items: center; + gap: 0.5rem; + margin-top: 1.25rem; + padding: 0.75rem 1.5rem; + background: var(--primary-color); + color: white; + text-decoration: none; + border-radius: var(--border-radius-md); + font-size: 1rem; + font-weight: 600; + transition: + background 0.2s, + transform 0.2s, + box-shadow 0.2s; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.topic-link:hover { + background: var(--primary-dark); + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); +} + +.topic-link::after { + content: "→"; + transition: transform 0.2s; +} + +.topic-link:hover::after { + transform: translateX(3px); +} + +/* Inline code in topic text */ +.topic-text code { + background: var(--primary-bg-light); + color: var(--primary-dark); + padding: 0.15rem 0.4rem; + border-radius: 4px; + font-family: "JetBrains Mono", "Fira Code", Consolas, monospace; + font-size: 0.9em; +} + +/* Code Examples */ +.topic-code { + position: sticky; + top: 1rem; +} + +.code-block { + background: #0d1117; + border-radius: var(--border-radius-md); + border: 1px solid #30363d; + overflow: hidden; +} + +.code-block pre { + margin: 0; + padding: 1rem; + overflow-x: auto; +} + +.code-block code { + font-family: "JetBrains Mono", "Fira Code", Consolas, monospace; + font-size: 0.8rem; + line-height: 1.6; + color: #e6edf3; + white-space: pre; +} + +.code-caption { + font-size: 0.75rem; + color: var(--light-text); + margin-top: 0.5rem; +} + +/* Responsive: stack on mobile */ +@media (max-width: 900px) { + .topic-row { + grid-template-columns: 1fr; + gap: 1rem; + } + + .topic-code { + position: static; + } +} + /* Module Grid */ .module-grid { display: grid;