From ad352aa986b440a95ace78a8f38a5895c8103897 Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Sat, 28 Mar 2026 19:25:32 +0100 Subject: [PATCH] fix: rewrite flexbox task descriptions to describe outcomes instead of answers (#3) Replace copy-pasteable CSS declarations in all 6 flexbox lesson tasks with outcome-oriented descriptions. Update validation error messages to hint at properties without revealing exact declarations. Add regex validation for flexbox-6 to accept both flex: 1 and flex-grow: 1. --- lessons/flexbox.json | 28 ++++++++++++------------- specs/003-flexbox-task-wording/tasks.md | 12 +++++------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lessons/flexbox.json b/lessons/flexbox.json index 6646dd2..b8f31e7 100644 --- a/lessons/flexbox.json +++ b/lessons/flexbox.json @@ -9,7 +9,7 @@ "id": "flexbox-1", "title": "Container", "description": "Before flexbox, creating even simple layouts required floats, positioning hacks, or table-based layouts. Flexbox (Flexible Box Layout) revolutionized CSS by providing a one-dimensional layout system designed specifically for distributing space and aligning content.

How it works: When you set display: flex on an element, it becomes a flex container. Its direct children automatically become flex items that flow along a main axis (horizontal by default). This single property transforms stacked block elements into a horizontal row.

The two axes:
Main axis – The primary direction items flow (row = left→right)
Cross axis – Perpendicular to main (row = top→bottom)

.nav {\n  display: flex;\n}
", - "task": "This navigation menu stacks vertically. Add display: flex to .nav to arrange the links horizontally.", + "task": "The navigation links are stacking vertically. Make them display side by side in a horizontal row.", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .nav { background: #1a1a2e; padding: 1rem; } .nav a { color: white; text-decoration: none; padding: 8px 1rem; border-radius: 4px; } .nav a:hover { background: rgba(255,255,255,0.1); }", "sandboxCSS": "", @@ -22,7 +22,7 @@ { "type": "property_value", "value": { "property": "display", "expected": "flex" }, - "message": "Set display: flex" + "message": "Try changing the display mode to create a flex container" } ] }, @@ -30,7 +30,7 @@ "id": "flexbox-2", "title": "Gap", "description": "The gap property adds consistent spacing between flex items without needing margins. It only creates space between items, not around the edges.", - "task": "Add gap: 1rem to space out the navigation links evenly.", + "task": "The navigation links are crammed together with no breathing room. Add 1rem of spacing between them.", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .nav { background: #1a1a2e; padding: 1rem; display: flex; } .nav a { color: white; text-decoration: none; padding: 8px 1rem; border-radius: 4px; background: rgba(255,255,255,0.1); }", "sandboxCSS": "", @@ -43,7 +43,7 @@ { "type": "property_value", "value": { "property": "gap", "expected": "1rem" }, - "message": "Set gap: 1rem" + "message": "Use the property that adds spacing between flex items" } ] }, @@ -51,7 +51,7 @@ "id": "flexbox-3", "title": "Justify Content", "description": "justify-content distributes items along the main axis. Common values:
flex-start – pack items at the start
flex-end – pack at the end
center – center items
space-between – equal space between items
space-around – equal space around items", - "task": "Push the \"Login\" button to the right by setting justify-content: space-between on the nav.", + "task": "The Login button should sit on the far right, with the other links staying on the left. Distribute the space between them.", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .nav { background: #1a1a2e; padding: 1rem; display: flex; } .links { display: flex; gap: 8px; } .nav a { color: white; text-decoration: none; padding: 8px 1rem; border-radius: 4px; } .nav a:hover { background: rgba(255,255,255,0.1); } .login { background: steelblue; }", "sandboxCSS": "", @@ -64,7 +64,7 @@ { "type": "property_value", "value": { "property": "justify-content", "expected": "space-between" }, - "message": "Set justify-content: space-between" + "message": "Use the property that distributes items along the main axis" } ] }, @@ -72,7 +72,7 @@ "id": "flexbox-4", "title": "Align Items", "description": "align-items controls alignment on the cross axis (vertical when flex-direction is row). Values include:
stretch – stretch to fill (default)
flex-start – align to top
flex-end – align to bottom
center – center vertically", - "task": "The logo and nav links have different heights. Center them vertically with align-items: center.", + "task": "The logo and nav links sit at different heights. Center them vertically so they line up.", "previewHTML": "
ACME
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .header { background: white; padding: 1rem 2rem; display: flex; justify-content: space-between; border-bottom: 1px solid #eee; } .logo { font-size: 1.5rem; font-weight: bold; color: steelblue; } nav { display: flex; gap: 1rem; } nav a { color: #333; text-decoration: none; font-size: 0.9rem; }", "sandboxCSS": "", @@ -85,7 +85,7 @@ { "type": "property_value", "value": { "property": "align-items", "expected": "center" }, - "message": "Set align-items: center" + "message": "Use the property that controls cross-axis alignment" } ] }, @@ -93,7 +93,7 @@ "id": "flexbox-5", "title": "Flex Wrap", "description": "By default, flex items squeeze onto one line. flex-wrap: wrap allows items to flow onto multiple lines when they run out of space.", - "task": "These cards overflow the container. Add flex-wrap: wrap to allow them to wrap to new rows.", + "task": "The cards overflow the container instead of fitting within it. Allow the items to flow onto new rows when they run out of space.", "previewHTML": "
Card 1
Card 2
Card 3
Card 4
Card 5
Card 6
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .cards { display: flex; gap: 1rem; } .card { background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); min-width: 120px; text-align: center; }", "sandboxCSS": "", @@ -106,7 +106,7 @@ { "type": "property_value", "value": { "property": "flex-wrap", "expected": "wrap" }, - "message": "Set flex-wrap: wrap" + "message": "Use the property that allows flex items to wrap onto new lines" } ] }, @@ -114,7 +114,7 @@ "id": "flexbox-6", "title": "Flex Grow", "description": "The flex property on items controls how they grow and shrink. flex: 1 makes an item grow to fill available space. Multiple items with flex: 1 share space equally.", - "task": "Make the search input expand to fill available space by setting flex: 1 on .search.", + "task": "The search input is too narrow. Make it stretch to fill all the remaining space in the toolbar.", "previewHTML": "
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .toolbar { display: flex; gap: 8px; padding: 1rem; background: #f5f5f5; border-radius: 8px; } .search { padding: 8px 1rem; border: 1px solid #ddd; border-radius: 4px; font-size: 1rem; } .btn { padding: 8px 1rem; background: steelblue; color: white; border: none; border-radius: 4px; cursor: pointer; }", "sandboxCSS": "", @@ -125,9 +125,9 @@ "previewContainer": "preview-area", "validations": [ { - "type": "property_value", - "value": { "property": "flex", "expected": "1" }, - "message": "Set flex: 1" + "type": "regex", + "value": "(flex\\s*:\\s*1|flex-grow\\s*:\\s*1)", + "message": "Use the property that makes a flex item grow to fill available space" } ] } diff --git a/specs/003-flexbox-task-wording/tasks.md b/specs/003-flexbox-task-wording/tasks.md index 3229d9c..bf9999d 100644 --- a/specs/003-flexbox-task-wording/tasks.md +++ b/specs/003-flexbox-task-wording/tasks.md @@ -1,13 +1,13 @@ # Tasks ## Phase 1: Core Content Changes -- [ ] Task 1.1: Rewrite task text for all 6 flexbox lessons to describe visual outcomes [P] -- [ ] Task 1.2: Rewrite validation error messages to hint without revealing answers [P] +- [X] Task 1.1: Rewrite task text for all 6 flexbox lessons to describe visual outcomes [P] +- [X] Task 1.2: Rewrite validation error messages to hint without revealing answers [P] ## Phase 2: Alternative Validations -- [ ] Task 2.1: Add regex validation for flexbox-6 to accept both `flex: 1` and `flex-grow: 1` +- [X] Task 2.1: Add regex validation for flexbox-6 to accept both `flex: 1` and `flex-grow: 1` ## Phase 3: Validation -- [ ] Task 3.1: Run existing test suite to confirm no regressions -- [ ] Task 3.2: Verify flexbox.json still conforms to module schema -- [ ] Task 3.3: Run lesson format check (`npm run format.lessons`) +- [X] Task 3.1: Run existing test suite to confirm no regressions +- [X] Task 3.2: Verify flexbox.json still conforms to module schema +- [X] Task 3.3: Run lesson format check (`npm run format.lessons`)