fix: improve lesson content with kbd tags, solutions, and animation contrast
- Add <kbd> tags to CSS property values and selectors in task descriptions - Add solution code to all lessons for better guidance - Improve animation contrast in transitions lesson (black/white instead of similar purples, dramatic color changes for visibility) - Simplify validation messages with kbd formatting
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "../schemas/code-crispies-module-schema.json",
|
||||
"id": "box-model",
|
||||
"title": "WIP: Padding, Borders, and Margins",
|
||||
"title": "Box Model",
|
||||
"description": "Master the fundamental principles of space management in web design through the CSS box model. This module explores how content, padding, borders, and margins combine to create layout structures that are both visually appealing and structurally sound.",
|
||||
"difficulty": "beginner",
|
||||
"lessons": [
|
||||
@@ -9,19 +9,20 @@
|
||||
"id": "box-model-1",
|
||||
"title": "Box Model Components",
|
||||
"description": "The CSS box model consists of four concentric layers: content area (innermost), padding, border, and margin (outermost). Understanding how these components interact is essential for precise layout control.",
|
||||
"task": "Add <code>padding: 1rem</code> to <code>.box</code> to create space between its content and border.",
|
||||
"task": "Add <kbd>padding: 1rem</kbd> to <kbd>.box</kbd> to create space between its content and border.",
|
||||
"previewHTML": "<div class=\"box\">Box Model Components</div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background-color: lavender; border: 2px dashed slategray; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": ".box {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "padding: 1rem;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "padding", "expected": "1rem" },
|
||||
"message": "Set padding to '1rem'"
|
||||
"message": "Set <kbd>padding: 1rem</kbd>"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -29,19 +30,20 @@
|
||||
"id": "box-model-2",
|
||||
"title": "Adding Borders",
|
||||
"description": "Borders outline an element, creating visual separation from surrounding content. The border shorthand accepts three values: width, style, and color.",
|
||||
"task": "Add <code>border: 2px solid darkslategray</code> to <code>.box</code>.",
|
||||
"task": "Add <kbd>border: 2px solid darkslategray</kbd> to <kbd>.box</kbd>.",
|
||||
"previewHTML": "<div class=\"box\">This box needs a border</div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background-color: mintcream; padding: 1rem; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": ".box {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "border: 2px solid darkslategray;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "border:\\s*2px\\s+solid\\s+darkslategray",
|
||||
"message": "Set border to '2px solid darkslategray'",
|
||||
"message": "Set <kbd>border: 2px solid darkslategray</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
}
|
||||
]
|
||||
@@ -50,39 +52,41 @@
|
||||
"id": "box-model-3",
|
||||
"title": "Adding Margins",
|
||||
"description": "Margins create space between elements, controlling how they relate to one another within a layout. Unlike padding (which affects internal spacing), margins exist outside the element's border.",
|
||||
"task": "Add <code>margin: 1rem</code> to <code>.margin-box</code> to create space between it and the adjacent element.",
|
||||
"task": "Add <kbd>margin: 1rem</kbd> to <kbd>.margin-box</kbd> to create space between it and the adjacent element.",
|
||||
"previewHTML": "<div class=\"container\"><div class=\"margin-box\">This box needs margins</div><div class=\"neighbor\">Adjacent element</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .container { background-color: whitesmoke; padding: 8px; } .margin-box { background-color: plum; padding: 1rem; border: 2px solid orchid; } .neighbor { background-color: lightblue; padding: 1rem; border: 2px solid steelblue; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": ".margin-box {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "margin: 1rem;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "margin", "expected": "1rem" },
|
||||
"message": "Set margin to '1rem'"
|
||||
"message": "Set <kbd>margin: 1rem</kbd>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "box-model-4",
|
||||
"title": "Box Sizing: Border-Box",
|
||||
"description": "The box-sizing property determines how element dimensions are calculated. The default 'content-box' excludes padding and border from width/height, while 'border-box' includes them, making layout calculations more intuitive.",
|
||||
"task": "Add <code>box-sizing: border-box</code> to <code>.border-box</code> so padding and border are included in its width.",
|
||||
"description": "The <kbd>box-sizing</kbd> property determines how element dimensions are calculated. The default <kbd>content-box</kbd> excludes padding and border from width/height, while <kbd>border-box</kbd> includes them, making layout calculations more intuitive.",
|
||||
"task": "Add <kbd>box-sizing: border-box</kbd> to <kbd>.border-box</kbd> so padding and border are included in its width.",
|
||||
"previewHTML": "<div class=\"sizing-demo\"><div class=\"box content-box\">Content-box (default)</div><div class=\"box border-box\">Border-box</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .sizing-demo { display: flex; gap: 1rem; } .box { width: 200px; padding: 1rem; border: 4px solid teal; background: lightcyan; } .content-box { box-sizing: content-box; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": ".border-box {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "box-sizing: border-box;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "box-sizing", "expected": "border-box" },
|
||||
"message": "Set box-sizing to 'border-box'"
|
||||
"message": "Set <kbd>box-sizing: border-box</kbd>"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -90,19 +94,20 @@
|
||||
"id": "box-model-5",
|
||||
"title": "Margin Collapse",
|
||||
"description": "When two vertical margins meet, they collapse to the larger value instead of adding up. Understanding this behavior is crucial for consistent vertical spacing.",
|
||||
"task": "Add <code>margin-bottom: 2rem</code> to <code>.first</code>. Notice the space between paragraphs equals 2rem (not 3rem) due to margin collapse.",
|
||||
"task": "Add <kbd>margin-bottom: 2rem</kbd> to <kbd>.first</kbd>. Notice the space between paragraphs equals 2rem (not 3rem) due to margin collapse.",
|
||||
"previewHTML": "<div class=\"collapse-demo\"><p class=\"first\">This paragraph has a bottom margin.</p><p class=\"second\">This paragraph has a top margin of 1rem.</p></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .collapse-demo { border: 1px solid silver; padding: 8px; background: ghostwhite; } .second { margin-top: 1rem; background: linen; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": ".first {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "margin-bottom: 2rem;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "margin-bottom", "expected": "2rem" },
|
||||
"message": "Set margin-bottom to '2rem'"
|
||||
"message": "Set <kbd>margin-bottom: 2rem</kbd>"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -110,19 +115,20 @@
|
||||
"id": "box-model-6",
|
||||
"title": "Margin Shorthand Notation",
|
||||
"description": "The margin shorthand can set all four sides at once. Two values set vertical (top/bottom) and horizontal (left/right) margins respectively.",
|
||||
"task": "Add <code>margin: 1rem 2rem</code> to <code>.shorthand-box</code> for 1rem top/bottom and 2rem left/right.",
|
||||
"task": "Add <kbd>margin: 1rem 2rem</kbd> to <kbd>.shorthand-box</kbd> for 1rem top/bottom and 2rem left/right.",
|
||||
"previewHTML": "<div class=\"container\"><div class=\"shorthand-box\">This box needs margins: 1rem top/bottom, 2rem left/right</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .container { background-color: whitesmoke; padding: 8px; } .shorthand-box { background-color: honeydew; border: 2px solid mediumseagreen; padding: 1rem; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": ".shorthand-box {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "margin: 1rem 2rem;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "margin:\\s*1rem\\s+2rem",
|
||||
"message": "Set margin to '1rem 2rem'",
|
||||
"message": "Set <kbd>margin: 1rem 2rem</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
}
|
||||
]
|
||||
@@ -131,39 +137,41 @@
|
||||
"id": "box-model-7",
|
||||
"title": "Padding Shorthand Notation",
|
||||
"description": "Like margin, padding shorthand allows setting all sides at once. A single value applies to all four sides equally.",
|
||||
"task": "Add <code>padding: 1.5rem</code> to <code>.padding-box</code> to add equal padding on all sides.",
|
||||
"task": "Add <kbd>padding: 1.5rem</kbd> to <kbd>.padding-box</kbd> to add equal padding on all sides.",
|
||||
"previewHTML": "<div class=\"padding-box\">This box needs equal padding on all sides</div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .padding-box { background-color: papayawhip; border: 2px solid orange; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": ".padding-box {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "padding: 1.5rem;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "padding", "expected": "1.5rem" },
|
||||
"message": "Set padding to '1.5rem'"
|
||||
"message": "Set <kbd>padding: 1.5rem</kbd>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "box-model-8",
|
||||
"title": "Border on Specific Sides",
|
||||
"description": "For granular control, you can target specific sides with border-top, border-right, border-bottom, or border-left.",
|
||||
"task": "Add <code>border-bottom: 4px solid dodgerblue</code> to <code>.border-demo</code>.",
|
||||
"description": "For granular control, you can target specific sides with <kbd>border-top</kbd>, <kbd>border-right</kbd>, <kbd>border-bottom</kbd>, or <kbd>border-left</kbd>.",
|
||||
"task": "Add <kbd>border-bottom: 4px solid dodgerblue</kbd> to <kbd>.border-demo</kbd>.",
|
||||
"previewHTML": "<div class=\"border-demo\">This element needs only a bottom border</div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .border-demo { padding: 1rem; background-color: aliceblue; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": ".border-demo {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "border-bottom: 4px solid dodgerblue;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "border-bottom:\\s*4px\\s+solid\\s+dodgerblue",
|
||||
"message": "Set border-bottom to '4px solid dodgerblue'",
|
||||
"message": "Set <kbd>border-bottom: 4px solid dodgerblue</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "../schemas/code-crispies-module-schema.json",
|
||||
"id": "units-variables",
|
||||
"title": "Units, var() and calc()",
|
||||
"title": "Units & Vars",
|
||||
"description": "Understand the variety of CSS measurement units and how to define and use custom properties for maintainable styles.",
|
||||
"difficulty": "beginner",
|
||||
"lessons": [
|
||||
@@ -9,36 +9,38 @@
|
||||
"id": "units-1",
|
||||
"title": "Absolute vs. Relative Units",
|
||||
"description": "Learn the difference between px, rem, em, %, and vw/vh for flexible, responsive layouts.",
|
||||
"task": "Set the width of '.unit-box' to 80% and max-width to 37.5rem.",
|
||||
"task": "Set the <kbd>width</kbd> of <kbd>.unit-box</kbd> to <kbd>80%</kbd> and <kbd>max-width</kbd> to <kbd>37.5rem</kbd>.",
|
||||
"previewHTML": "<div class=\"unit-box\">Resize me!</div>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .unit-box { background: #f5f5f5; padding: 1rem; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Set flexible sizing */\n.unit-box {",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "}",
|
||||
"solution": " width: 80%;\n max-width: 37.5rem;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{ "type": "contains", "value": "width", "message": "Use 'width' property", "options": { "caseSensitive": false } },
|
||||
{ "type": "property_value", "value": { "property": "width", "expected": "80%" }, "message": "Set width to '80%'" },
|
||||
{ "type": "contains", "value": "max-width", "message": "Use 'max-width' property", "options": { "caseSensitive": false } },
|
||||
{ "type": "property_value", "value": { "property": "max-width", "expected": "37.5rem" }, "message": "Set max-width to '37.5rem'" }
|
||||
{ "type": "contains", "value": "width", "message": "Use <kbd>width</kbd> property", "options": { "caseSensitive": false } },
|
||||
{ "type": "property_value", "value": { "property": "width", "expected": "80%" }, "message": "Set width to <kbd>80%</kbd>" },
|
||||
{ "type": "contains", "value": "max-width", "message": "Use <kbd>max-width</kbd> property", "options": { "caseSensitive": false } },
|
||||
{ "type": "property_value", "value": { "property": "max-width", "expected": "37.5rem" }, "message": "Set max-width to <kbd>37.5rem</kbd>" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "units-2",
|
||||
"title": "CSS Custom Properties",
|
||||
"description": "Define and reuse variables (--custom properties) to centralize your theme values.",
|
||||
"task": "Create a <code>--main-color</code> variable in :root with #6200ee and apply it as the border color on '.var-box'.",
|
||||
"task": "Create a <kbd>--main-color</kbd> variable in <kbd>:root</kbd> with <kbd>#6200ee</kbd> and apply it as the border color on <kbd>.var-box</kbd>.",
|
||||
"previewHTML": "<div class=\"var-box\">Variable Box</div>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .var-box { padding: 1rem; border: 0.125rem solid #ddd; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Define and use a CSS variable */\n:root {",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "}\n.var-box { }",
|
||||
"solution": " --main-color: #6200ee;\n}\n.var-box {\n border-color: var(--main-color);",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{ "type": "contains", "value": "--main-color", "message": "Define '--main-color' in :root", "options": { "caseSensitive": false } },
|
||||
{ "type": "contains", "value": "var(--main-color)", "message": "Use var(--main-color)", "options": { "caseSensitive": false } },
|
||||
{ "type": "contains", "value": "--main-color", "message": "Define <kbd>--main-color</kbd> in :root", "options": { "caseSensitive": false } },
|
||||
{ "type": "contains", "value": "var(--main-color)", "message": "Use <kbd>var(--main-color)</kbd>", "options": { "caseSensitive": false } },
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "border", "expected": "var(--main-color)" },
|
||||
@@ -50,27 +52,28 @@
|
||||
{
|
||||
"id": "units-3",
|
||||
"title": "Unit Calculations (calc)",
|
||||
"description": "Use the <code>calc()</code> function to combine different units in one expression.",
|
||||
"task": "Set the width of '.calc-box' to calc(100% - 2rem) and min-height to calc(10vh + 1rem).",
|
||||
"description": "Use the <kbd>calc()</kbd> function to combine different units in one expression.",
|
||||
"task": "Set the <kbd>width</kbd> of <kbd>.calc-box</kbd> to <kbd>calc(100% - 2rem)</kbd> and <kbd>min-height</kbd> to <kbd>calc(10vh + 1rem)</kbd>.",
|
||||
"previewHTML": "<div class=\"calc-box\">Calc Demo</div>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .calc-box { background: #e8f5e9; padding: 1rem; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Use calc for dynamic sizing */\n.calc-box {",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "}",
|
||||
"solution": " width: calc(100% - 2rem);\n min-height: calc(10vh + 1rem);",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{ "type": "contains", "value": "calc", "message": "Use 'calc()' function", "options": { "caseSensitive": false } },
|
||||
{ "type": "contains", "value": "calc", "message": "Use <kbd>calc()</kbd> function", "options": { "caseSensitive": false } },
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "width:\\s*calc\\(100% - 2rem\\)",
|
||||
"message": "Width should be calc(100% - 2rem)",
|
||||
"message": "Width should be <kbd>calc(100% - 2rem)</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
},
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "min-height:\\s*calc\\(10vh \\+ 1rem\\)",
|
||||
"message": "Min-height should be calc(10vh + 1rem)",
|
||||
"message": "Min-height should be <kbd>calc(10vh + 1rem)</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
}
|
||||
]
|
||||
@@ -79,19 +82,20 @@
|
||||
"id": "units-4",
|
||||
"title": "Viewport & Responsive Units",
|
||||
"description": "Control layouts relative to viewport size with vw, vh, and vmin/vmax units.",
|
||||
"task": "Give '.viewport-box' a width of 50vw and height of 20vh.",
|
||||
"task": "Give <kbd>.viewport-box</kbd> a <kbd>width</kbd> of <kbd>50vw</kbd> and <kbd>height</kbd> of <kbd>20vh</kbd>.",
|
||||
"previewHTML": "<div class=\"viewport-box\">Viewport Box</div>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .viewport-box { background: #ffe0b2; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Use viewport units */\n.viewport-box {",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "}",
|
||||
"solution": " width: 50vw;\n height: 20vh;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{ "type": "contains", "value": "vw", "message": "Use 'vw' unit", "options": { "caseSensitive": false } },
|
||||
{ "type": "contains", "value": "vh", "message": "Use 'vh' unit", "options": { "caseSensitive": false } },
|
||||
{ "type": "property_value", "value": { "property": "width", "expected": "50vw" }, "message": "Set width to '50vw'" },
|
||||
{ "type": "property_value", "value": { "property": "height", "expected": "20vh" }, "message": "Set height to '20vh'" }
|
||||
{ "type": "contains", "value": "vw", "message": "Use <kbd>vw</kbd> unit", "options": { "caseSensitive": false } },
|
||||
{ "type": "contains", "value": "vh", "message": "Use <kbd>vh</kbd> unit", "options": { "caseSensitive": false } },
|
||||
{ "type": "property_value", "value": { "property": "width", "expected": "50vw" }, "message": "Set width to <kbd>50vw</kbd>" },
|
||||
{ "type": "property_value", "value": { "property": "height", "expected": "20vh" }, "message": "Set height to <kbd>20vh</kbd>" }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,129 +1,128 @@
|
||||
{
|
||||
"$schema": "../schemas/code-crispies-module-schema.json",
|
||||
"id": "transitions-animations",
|
||||
"title": "Transitions & Animations",
|
||||
"title": "Animations",
|
||||
"description": "Bring interactivity to your UI by smoothly transitioning properties and creating keyframe-driven animations.",
|
||||
"difficulty": "beginner",
|
||||
"lessons": [
|
||||
{
|
||||
"id": "transitions-1",
|
||||
"title": "Simple Transitions",
|
||||
"description": "Learn how to apply <code>transition</code> to properties for smooth changes on state changes.",
|
||||
"task": "Add a hover transition on a button so its background-color fades over 0.3s.",
|
||||
"title": "Transitions",
|
||||
"description": "Learn how to apply <kbd>transition</kbd> to properties for smooth changes on state changes.",
|
||||
"task": "Add <kbd>transition: background-color 0.3s</kbd> to <kbd>.btn</kbd> so the color fades smoothly on hover.",
|
||||
"previewHTML": "<button class=\"btn\">Hover Me</button>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .btn { background: #6200ee; color: white; padding: 0.5rem 1rem; border: none; } .btn:hover { background: #3700b3; }",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .btn { background: black; color: white; padding: 0.5rem 1rem; border: none; cursor: pointer; } .btn:hover { background: white; color: black; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Add transition */\n.btn {",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "}",
|
||||
"solution": " transition: background-color 0.3s;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{ "type": "contains", "value": "transition", "message": "Use the 'transition' property", "options": { "caseSensitive": false } },
|
||||
{ "type": "contains", "value": "transition", "message": "Use the <kbd>transition</kbd> property", "options": { "caseSensitive": false } },
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "transition:\\s*background-color\\s*0\\.3s",
|
||||
"message": "Transition background-color over 0.3s",
|
||||
"message": "Set <kbd>transition: background-color 0.3s</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "transitions-2",
|
||||
"title": "Transition Timing Functions",
|
||||
"description": "Explore easing functions like ease, linear, ease-in, ease-out to control animation pacing.",
|
||||
"task": "Modify the button to use 'ease-in-out' timing for its transition.",
|
||||
"title": "Timing Funcs",
|
||||
"description": "Explore easing functions like <kbd>ease</kbd>, <kbd>linear</kbd>, <kbd>ease-in</kbd>, <kbd>ease-out</kbd> to control animation pacing.",
|
||||
"task": "Set <kbd>transition-timing-function</kbd> to <kbd>ease-in-out</kbd> on <kbd>.btn</kbd>.",
|
||||
"previewHTML": "<button class=\"btn\">Timing</button>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .btn { background: #6200ee; color: white; padding: 0.5rem 1rem; border: none; transition: background-color 0.3s; } .btn:hover { background: #03dac6; }",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .btn { background: navy; color: gold; padding: 0.5rem 1rem; border: none; cursor: pointer; transition: all 0.5s; } .btn:hover { background: gold; color: navy; transform: scale(1.1); }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Set timing function */\n.btn {",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "}",
|
||||
"solution": " transition-timing-function: ease-in-out;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "transition-timing-function",
|
||||
"message": "Use 'transition-timing-function'",
|
||||
"message": "Use <kbd>transition-timing-function</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
},
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "transition-timing-function", "expected": "ease-in-out" },
|
||||
"message": "Set timing to 'ease-in-out'"
|
||||
"message": "Set timing to <kbd>ease-in-out</kbd>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "transitions-3",
|
||||
"title": "Keyframe Animations Basics",
|
||||
"description": "Create named animations using <code>@keyframes</code> and apply them via the <code>animation</code> shorthand.",
|
||||
"task": "Define a keyframe named 'bounce' that moves an element up 20px at 50% and apply it to '.ball' over 1s infinite.",
|
||||
"title": "Keyframes",
|
||||
"description": "Create named animations using <kbd>@keyframes</kbd> and apply them via the <kbd>animation</kbd> shorthand.",
|
||||
"task": "Define a keyframe at <kbd>50%</kbd> with <kbd>transform: translateY(-20px)</kbd> and apply <kbd>animation: bounce 1s infinite</kbd> to <kbd>.ball</kbd>.",
|
||||
"previewHTML": "<div class=\"ball\"></div>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .ball { width: 50px; height: 50px; background: #ff0266; border-radius: 50%; margin: 2rem auto; }",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .ball { width: 50px; height: 50px; background: crimson; border-radius: 50%; margin: 2rem auto; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Define keyframes and apply animation */\n@keyframes bounce {",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "}\n.ball { }",
|
||||
"solution": " 50% { transform: translateY(-20px); }\n}\n.ball {\n animation: bounce 1s infinite;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{ "type": "contains", "value": "@keyframes bounce", "message": "Define '@keyframes bounce'", "options": { "caseSensitive": false } },
|
||||
{ "type": "contains", "value": "@keyframes bounce", "message": "Define <kbd>@keyframes bounce</kbd>", "options": { "caseSensitive": false } },
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "50%.*transform: translateY\\(-20px\\)",
|
||||
"message": "At 50%, move up 20px",
|
||||
"message": "At <kbd>50%</kbd>, use <kbd>transform: translateY(-20px)</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
},
|
||||
{ "type": "contains", "value": "animation", "message": "Use 'animation' property on .ball", "options": { "caseSensitive": false } },
|
||||
{ "type": "contains", "value": "animation", "message": "Use <kbd>animation</kbd> property on <kbd>.ball</kbd>", "options": { "caseSensitive": false } },
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "animation:.*bounce.*1s.*infinite",
|
||||
"message": "Apply 'bounce 1s infinite'",
|
||||
"message": "Apply <kbd>animation: bounce 1s infinite</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "transitions-4",
|
||||
"title": "Animation Properties Deep Dive",
|
||||
"description": "Fine-tune animations with delay, iteration-count, direction, and fill-mode.",
|
||||
"task": "Animate '.box' using a 'fade' keyframe over 2s, delay 1s, run twice, and remain visible after.",
|
||||
"previewHTML": "<div class=\"box\">Fade Demo</div>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .box { width: 100px; height: 100px; background: #4caf50; margin: 2rem auto; }",
|
||||
"title": "Anim Properties",
|
||||
"description": "Fine-tune animations with <kbd>animation-delay</kbd>, <kbd>animation-iteration-count</kbd>, <kbd>animation-direction</kbd>, and <kbd>animation-fill-mode</kbd>.",
|
||||
"task": "Apply the <kbd>pulse</kbd> animation to <kbd>.box</kbd> with <kbd>animation-name: pulse</kbd>, <kbd>animation-duration: 2s</kbd>, <kbd>animation-delay: 1s</kbd>, <kbd>animation-iteration-count: 2</kbd>, and <kbd>animation-fill-mode: forwards</kbd>.",
|
||||
"previewHTML": "<div class=\"box\">Pulse</div>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .box { width: 100px; height: 100px; background: black; color: white; display: flex; align-items: center; justify-content: center; margin: 2rem auto; } @keyframes pulse { 0% { background: black; color: white; transform: scale(1); } 50% { background: white; color: black; transform: scale(1.2); } 100% { background: limegreen; color: black; transform: scale(1); } }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Define fade and set properties */\n@keyframes fade { from { opacity: 0; } to { opacity: 1; } }\n.box {",
|
||||
"codePrefix": "/* Apply animation properties */\n.box {",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "}",
|
||||
"solution": " animation-name: pulse;\n animation-duration: 2s;\n animation-delay: 1s;\n animation-iteration-count: 2;\n animation-fill-mode: forwards;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "animation-delay",
|
||||
"message": "Use 'animation-delay' property",
|
||||
"options": { "caseSensitive": false }
|
||||
"type": "property_value",
|
||||
"value": { "property": "animation-name", "expected": "pulse" },
|
||||
"message": "Set <kbd>animation-name: pulse</kbd>"
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "animation-iteration-count",
|
||||
"message": "Use 'animation-iteration-count' property",
|
||||
"options": { "caseSensitive": false }
|
||||
"type": "property_value",
|
||||
"value": { "property": "animation-duration", "expected": "2s" },
|
||||
"message": "Set <kbd>animation-duration: 2s</kbd>"
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "animation-fill-mode",
|
||||
"message": "Use 'animation-fill-mode' property",
|
||||
"options": { "caseSensitive": false }
|
||||
"type": "property_value",
|
||||
"value": { "property": "animation-delay", "expected": "1s" },
|
||||
"message": "Set <kbd>animation-delay: 1s</kbd>"
|
||||
},
|
||||
{ "type": "property_value", "value": { "property": "animation-duration", "expected": "2s" }, "message": "Duration should be 2s" },
|
||||
{ "type": "property_value", "value": { "property": "animation-delay", "expected": "1s" }, "message": "Delay should be 1s" },
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "animation-iteration-count", "expected": "2" },
|
||||
"message": "Iteration count should be 2"
|
||||
"message": "Set <kbd>animation-iteration-count: 2</kbd>"
|
||||
},
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "animation-fill-mode", "expected": "forwards" },
|
||||
"message": "Fill mode should be forwards"
|
||||
"message": "Set <kbd>animation-fill-mode: forwards</kbd>"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,114 +1,118 @@
|
||||
{
|
||||
"$schema": "../schemas/code-crispies-module-schema.json",
|
||||
"id": "responsive-design",
|
||||
"title": "Responsive Design & Media Queries",
|
||||
"title": "Responsive",
|
||||
"description": "Make your layouts adapt to different screen sizes using media queries and fluid design techniques.",
|
||||
"difficulty": "intermediate",
|
||||
"lessons": [
|
||||
{
|
||||
"id": "responsive-1",
|
||||
"title": "Introduction to Media Queries",
|
||||
"title": "Media Queries",
|
||||
"description": "Understand the syntax and use cases for CSS media queries to apply styles conditionally based on viewport characteristics.",
|
||||
"task": "Write a media query that applies when the viewport is at most 600px wide and changes the background of '.responsive-box' to lightcoral.",
|
||||
"task": "Write a media query with <kbd>@media (max-width: 600px)</kbd> that changes <kbd>.responsive-box</kbd> background to <kbd>lightcoral</kbd>.",
|
||||
"previewHTML": "<div class=\"responsive-box\">Resize the window</div>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .responsive-box { padding: 1rem; background: lightblue; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Add your media query below */\n",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "",
|
||||
"solution": "@media (max-width: 600px) {\n .responsive-box {\n background: lightcoral;\n }\n}",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "@media\\s*\\(max-width:\\s*600px\\)",
|
||||
"message": "Use a media query for max-width: 600px",
|
||||
"message": "Use <kbd>@media (max-width: 600px)</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": ".responsive-box",
|
||||
"message": "Target '.responsive-box' inside the media query",
|
||||
"message": "Target <kbd>.responsive-box</kbd> inside the media query",
|
||||
"options": { "caseSensitive": false }
|
||||
},
|
||||
{ "type": "contains", "value": "background", "message": "Change the 'background' property", "options": { "caseSensitive": false } },
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "background", "expected": "lightcoral" },
|
||||
"message": "Set background to 'lightcoral'",
|
||||
"message": "Set <kbd>background: lightcoral</kbd>",
|
||||
"options": { "exact": false }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "responsive-2",
|
||||
"title": "Fluid Typography",
|
||||
"description": "Use relative units like vw to make font sizes scale with the viewport width.",
|
||||
"task": "Set the font-size of '.fluid-text' to 5vw so it scales as the viewport changes.",
|
||||
"title": "Fluid Type",
|
||||
"description": "Use relative units like <kbd>vw</kbd> to make font sizes scale with the viewport width.",
|
||||
"task": "Set <kbd>font-size: 5vw</kbd> on <kbd>.fluid-text</kbd> so it scales as the viewport changes.",
|
||||
"previewHTML": "<p class=\"fluid-text\">Fluid Typography</p>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Apply fluid font sizing */\n.fluid-text {",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "}",
|
||||
"solution": " font-size: 5vw;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{ "type": "contains", "value": "font-size", "message": "Use 'font-size' property", "options": { "caseSensitive": false } },
|
||||
{ "type": "contains", "value": "vw", "message": "Use 'vw' unit for fluid sizing", "options": { "caseSensitive": false } },
|
||||
{ "type": "property_value", "value": { "property": "font-size", "expected": "5vw" }, "message": "Set font-size to '5vw'" }
|
||||
{ "type": "property_value", "value": { "property": "font-size", "expected": "5vw" }, "message": "Set <kbd>font-size: 5vw</kbd>" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "responsive-3",
|
||||
"title": "Flexible Grids",
|
||||
"description": "Combine CSS Grid with auto-fit or auto-fill for responsive column layouts.",
|
||||
"task": "Define '.grid-responsive' with grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); and a gap of 1rem.",
|
||||
"title": "Flex Grids",
|
||||
"description": "Combine CSS Grid with <kbd>auto-fit</kbd> or <kbd>auto-fill</kbd> for responsive column layouts.",
|
||||
"task": "Add <kbd>display: grid</kbd>, <kbd>grid-template-columns: repeat(auto-fit, minmax(200px, 1fr))</kbd>, and <kbd>gap: 1rem</kbd> to <kbd>.grid-responsive</kbd>.",
|
||||
"previewHTML": "<div class=\"grid-responsive\"><div>1</div><div>2</div><div>3</div><div>4</div></div>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .grid-responsive > div { background: #d1c4e9; padding: 1rem; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Create a responsive grid */\n.grid-responsive {",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "}",
|
||||
"solution": " display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 1rem;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "grid-template-columns",
|
||||
"message": "Define 'grid-template-columns'",
|
||||
"options": { "caseSensitive": false }
|
||||
"type": "property_value",
|
||||
"value": { "property": "display", "expected": "grid" },
|
||||
"message": "Set <kbd>display: grid</kbd>"
|
||||
},
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "repeat\\(auto-fit,\\s*minmax\\(200px,\\s*1fr\\)\\)",
|
||||
"message": "Use repeat(auto-fit, minmax(200px, 1fr))",
|
||||
"message": "Use <kbd>repeat(auto-fit, minmax(200px, 1fr))</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
},
|
||||
{ "type": "contains", "value": "gap", "message": "Use 'gap' property", "options": { "caseSensitive": false } }
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "gap", "expected": "1rem" },
|
||||
"message": "Set <kbd>gap: 1rem</kbd>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "responsive-4",
|
||||
"title": "Mobile-First Media Queries",
|
||||
"title": "Mobile-First",
|
||||
"description": "Adopt a mobile-first approach by writing base styles for small screens and enhancing for larger viewports.",
|
||||
"task": "Write a media query for min-width 768px that sets '.sidebar' width to 250px.",
|
||||
"task": "Write a media query with <kbd>@media (min-width: 768px)</kbd> that sets <kbd>.sidebar</kbd> width to <kbd>250px</kbd>.",
|
||||
"previewHTML": "<aside class=\"sidebar\">Sidebar</aside>",
|
||||
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .sidebar { background: #c8e6c9; padding: 1rem; }",
|
||||
"sandboxCSS": "",
|
||||
"codePrefix": "/* Add mobile-first enhancement */\n",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "",
|
||||
"solution": "@media (min-width: 768px) {\n .sidebar {\n width: 250px;\n }\n}",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "@media\\s*\\(min-width:\\s*768px\\)",
|
||||
"message": "Use a media query for min-width: 768px",
|
||||
"message": "Use <kbd>@media (min-width: 768px)</kbd>",
|
||||
"options": { "caseSensitive": false }
|
||||
},
|
||||
{ "type": "contains", "value": ".sidebar", "message": "Target '.sidebar' inside media query", "options": { "caseSensitive": false } },
|
||||
{ "type": "contains", "value": ".sidebar", "message": "Target <kbd>.sidebar</kbd> inside media query", "options": { "caseSensitive": false } },
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": { "property": "width", "expected": "250px" },
|
||||
"message": "Set width to '250px'",
|
||||
"message": "Set <kbd>width: 250px</kbd>",
|
||||
"options": { "exact": false }
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
{
|
||||
"$schema": "../schemas/code-crispies-module-schema.json",
|
||||
"id": "flexbox",
|
||||
"title": "CSS Flexbox",
|
||||
"title": "Flexbox",
|
||||
"description": "Master the flexible box layout model for modern responsive designs",
|
||||
"difficulty": "intermediate",
|
||||
"lessons": [
|
||||
{
|
||||
"id": "flexbox-1",
|
||||
"title": "Flexbox Container Basics",
|
||||
"title": "Container",
|
||||
"description": "Learn how to create a flex container and understand the main and cross axes.",
|
||||
"task": "Add <code>display: flex</code> to <code>.flex-container</code> to create a flexbox layout.",
|
||||
"task": "Add <kbd>display: flex</kbd> to <kbd>.flex-container</kbd> to create a flexbox layout.",
|
||||
"previewHTML": "<div class='flex-container'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background: steelblue; color: white; padding: 1rem; margin: 8px; text-align: center; font-weight: bold; }",
|
||||
"sandboxCSS": ".flex-container { border: 2px dashed #aaa; padding: 1rem; }",
|
||||
"codePrefix": ".flex-container {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "display: flex;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
@@ -24,46 +25,31 @@
|
||||
"property": "display",
|
||||
"expected": "flex"
|
||||
},
|
||||
"message": "Set display to 'flex'"
|
||||
"message": "Set <kbd>display: flex</kbd>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flexbox-2",
|
||||
"title": "Flex Direction and Wrap",
|
||||
"title": "Direction & Wrap",
|
||||
"description": "Control the direction and wrapping of flex items within a container.",
|
||||
"task": "Add <code>flex-direction: column</code> and <code>flex-wrap: wrap</code> to <code>.flex-container</code>.",
|
||||
"task": "Add <kbd>flex-direction: column</kbd> and <kbd>flex-wrap: wrap</kbd> to <kbd>.flex-container</kbd>.",
|
||||
"previewHTML": "<div class='flex-container'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div><div class='box'>4</div><div class='box'>5</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background: steelblue; color: white; padding: 1rem; margin: 8px; text-align: center; font-weight: bold; width: 3rem; height: 3rem; display: flex; align-items: center; justify-content: center; }",
|
||||
"sandboxCSS": ".flex-container { border: 2px dashed #aaa; padding: 1rem; height: 16rem; display: flex; }",
|
||||
"codePrefix": ".flex-container {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "flex-direction: column;\n flex-wrap: wrap;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "flex-direction",
|
||||
"message": "Use the 'flex-direction' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "flex-wrap",
|
||||
"message": "Use the 'flex-wrap' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": {
|
||||
"property": "flex-direction",
|
||||
"expected": "column"
|
||||
},
|
||||
"message": "Set the flex-direction to 'column'",
|
||||
"message": "Set <kbd>flex-direction: column</kbd>",
|
||||
"options": {
|
||||
"exact": true
|
||||
}
|
||||
@@ -74,7 +60,7 @@
|
||||
"property": "flex-wrap",
|
||||
"expected": "wrap"
|
||||
},
|
||||
"message": "Set flex-wrap to 'wrap'",
|
||||
"message": "Set <kbd>flex-wrap: wrap</kbd>",
|
||||
"options": {
|
||||
"exact": true
|
||||
}
|
||||
@@ -85,30 +71,23 @@
|
||||
"id": "flexbox-3",
|
||||
"title": "Justify Content",
|
||||
"description": "Learn how to align flex items along the main axis of the flex container.",
|
||||
"task": "Add <code>justify-content: space-between</code> to <code>.flex-container</code> to distribute the boxes evenly.",
|
||||
"task": "Add <kbd>justify-content: space-between</kbd> to <kbd>.flex-container</kbd> to distribute the boxes evenly.",
|
||||
"previewHTML": "<div class='flex-container'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background: steelblue; color: white; padding: 1rem; text-align: center; font-weight: bold; width: 3rem; height: 3rem; display: flex; align-items: center; justify-content: center; }",
|
||||
"sandboxCSS": ".flex-container { border: 2px dashed #aaa; padding: 1rem; display: flex; }",
|
||||
"codePrefix": ".flex-container {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "justify-content: space-between;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "justify-content",
|
||||
"message": "Use the 'justify-content' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": {
|
||||
"property": "justify-content",
|
||||
"expected": "space-between"
|
||||
},
|
||||
"message": "Set justify-content to 'space-between'",
|
||||
"message": "Set <kbd>justify-content: space-between</kbd>",
|
||||
"options": {
|
||||
"exact": true
|
||||
}
|
||||
@@ -119,30 +98,23 @@
|
||||
"id": "flexbox-4",
|
||||
"title": "Align Items",
|
||||
"description": "Control how flex items are aligned along the cross axis of the flex container.",
|
||||
"task": "Add <code>align-items: center</code> to <code>.flex-container</code> to vertically center the boxes.",
|
||||
"task": "Add <kbd>align-items: center</kbd> to <kbd>.flex-container</kbd> to vertically center the boxes.",
|
||||
"previewHTML": "<div class='flex-container'><div class='box tall'>1</div><div class='box'>2</div><div class='box short'>3</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background: steelblue; color: white; padding: 1rem; margin: 8px; text-align: center; font-weight: bold; width: 3rem; display: flex; justify-content: center; } .tall { height: 6rem; } .short { height: 3rem; }",
|
||||
"sandboxCSS": ".flex-container { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 10rem; }",
|
||||
"codePrefix": ".flex-container {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "align-items: center;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "align-items",
|
||||
"message": "Use the 'align-items' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": {
|
||||
"property": "align-items",
|
||||
"expected": "center"
|
||||
},
|
||||
"message": "Set align-items to 'center'",
|
||||
"message": "Set <kbd>align-items: center</kbd>",
|
||||
"options": {
|
||||
"exact": true
|
||||
}
|
||||
@@ -152,14 +124,15 @@
|
||||
{
|
||||
"id": "flexbox-5",
|
||||
"title": "Flex Grow",
|
||||
"description": "The <code>flex</code> property controls how much an item grows relative to others.",
|
||||
"task": "Add <code>flex: 2</code> to <code>.box2</code> to make it grow twice as wide.",
|
||||
"description": "The <kbd>flex</kbd> property controls how much an item grows relative to others.",
|
||||
"task": "Add <kbd>flex: 2</kbd> to <kbd>.box2</kbd> to make it grow twice as wide.",
|
||||
"previewHTML": "<div class='flex-container'><div class='box box1'>1</div><div class='box box2'>2</div><div class='box box3'>3</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { color: white; padding: 1rem; margin: 8px; text-align: center; font-weight: bold; display: flex; align-items: center; justify-content: center; } .box1 { background: coral; flex: 1; } .box2 { background: mediumseagreen; } .box3 { background: gold; flex: 1; }",
|
||||
"sandboxCSS": ".flex-container { border: 2px dashed #aaa; padding: 1rem; display: flex; }",
|
||||
"codePrefix": ".box2 {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "flex: 2;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
@@ -168,21 +141,22 @@
|
||||
"property": "flex",
|
||||
"expected": "2"
|
||||
},
|
||||
"message": "Set flex to '2'"
|
||||
"message": "Set <kbd>flex: 2</kbd>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "flexbox-6",
|
||||
"title": "Align Self",
|
||||
"description": "Use <code>align-self</code> to override alignment for a single flex item.",
|
||||
"task": "Add <code>align-self: flex-start</code> to <code>.middle</code> to move it to the top.",
|
||||
"description": "Use <kbd>align-self</kbd> to override alignment for a single flex item.",
|
||||
"task": "Add <kbd>align-self: flex-start</kbd> to <kbd>.middle</kbd> to move it to the top.",
|
||||
"previewHTML": "<div class='flex-container'><div class='box'>1</div><div class='box middle'>2</div><div class='box'>3</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .box { background: steelblue; color: white; padding: 1rem; margin: 8px; text-align: center; font-weight: bold; width: 3rem; height: 3rem; display: flex; align-items: center; justify-content: center; } .middle { background: mediumseagreen; }",
|
||||
"sandboxCSS": ".flex-container { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 12rem; align-items: center; }",
|
||||
"codePrefix": ".middle {\n ",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "align-self: flex-start;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
@@ -191,7 +165,7 @@
|
||||
"property": "align-self",
|
||||
"expected": "flex-start"
|
||||
},
|
||||
"message": "Set align-self to 'flex-start'"
|
||||
"message": "Set <kbd>align-self: flex-start</kbd>"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "../schemas/code-crispies-module-schema.json",
|
||||
"id": "grid",
|
||||
"title": "CSS Grid",
|
||||
"title": "Grid",
|
||||
"description": "Master the grid layout system for complex two-dimensional layouts",
|
||||
"difficulty": "intermediate",
|
||||
"lessons": [
|
||||
@@ -9,43 +9,20 @@
|
||||
"id": "grid-1",
|
||||
"title": "Grid Container Basics",
|
||||
"description": "Learn how to create a grid container and define basic grid structures.",
|
||||
"task": "Create a grid with 3 columns of equal width and a 1rem gap between grid items.",
|
||||
"task": "Create a <kbd>.grid-container</kbd> with <kbd>display: grid</kbd>, <kbd>grid-template-columns: repeat(3, 1fr)</kbd>, and <kbd>gap: 1rem</kbd>.",
|
||||
"previewHTML": "<div class='grid-container'><div class='item'>1</div><div class='item'>2</div><div class='item'>3</div><div class='item'>4</div><div class='item'>5</div><div class='item'>6</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .item { background-color: #9b59b6; color: white; padding: 1.25rem; text-align: center; font-weight: bold; }",
|
||||
"sandboxCSS": ".grid-container { border: 0.125rem dashed #ccc; padding: 1rem; }",
|
||||
"codePrefix": "/* Create a grid with 3 equal columns and gap */\n",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "",
|
||||
"solution": ".grid-container {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 1rem;\n}",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": ".grid-container",
|
||||
"message": "Use the '.grid-container' class selector",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "display",
|
||||
"message": "Use the 'display' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "grid-template-columns",
|
||||
"message": "Use the 'grid-template-columns' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "gap",
|
||||
"message": "Use the 'gap' property",
|
||||
"message": "Use the <kbd>.grid-container</kbd> class selector",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
@@ -56,7 +33,7 @@
|
||||
"property": "display",
|
||||
"expected": "grid"
|
||||
},
|
||||
"message": "Set display to 'grid'",
|
||||
"message": "Set <kbd>display: grid</kbd>",
|
||||
"options": {
|
||||
"exact": true
|
||||
}
|
||||
@@ -64,7 +41,7 @@
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "grid-template-columns:\\s*repeat\\(\\s*3\\s*,\\s*1fr\\s*\\)",
|
||||
"message": "Set grid-template-columns to 'repeat(3, 1fr)'",
|
||||
"message": "Set <kbd>grid-template-columns: repeat(3, 1fr)</kbd>",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
@@ -75,7 +52,7 @@
|
||||
"property": "gap",
|
||||
"expected": "1rem"
|
||||
},
|
||||
"message": "Set gap to '1rem'",
|
||||
"message": "Set <kbd>gap: 1rem</kbd>",
|
||||
"options": {
|
||||
"exact": true
|
||||
}
|
||||
@@ -86,51 +63,20 @@
|
||||
"id": "grid-2",
|
||||
"title": "Grid Template Areas",
|
||||
"description": "Use named grid areas to create visual layouts that are easy to understand.",
|
||||
"task": "Create a layout with a header, sidebar, main content area, and footer using grid-template-areas.",
|
||||
"task": "Add <kbd>grid-template-areas</kbd> to create a layout with <kbd>header</kbd> spanning full width, <kbd>sidebar</kbd> and <kbd>content</kbd> in middle, and <kbd>footer</kbd> spanning full width.",
|
||||
"previewHTML": "<div class='grid-layout'><div class='header'>Header</div><div class='sidebar'>Sidebar</div><div class='content'>Main Content</div><div class='footer'>Footer</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .grid-layout > div { padding: 1.25rem; color: white; text-align: center; font-weight: bold; } .header { background-color: #e74c3c; } .sidebar { background-color: #3498db; } .content { background-color: #2ecc71; } .footer { background-color: #f39c12; }",
|
||||
"sandboxCSS": ".grid-layout { border: 0.125rem dashed #ccc; padding: 1rem; height: 25rem; }",
|
||||
"codePrefix": "/* Create a layout using grid-template-areas */\n.grid-layout {\n display: grid;\n grid-template-columns: 12rem 1fr;\n grid-template-rows: auto 1fr auto;\n gap: 1rem;\n \n /* Add your grid-template-areas code below */\n",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}\n\n/* Define which element goes in which grid area */\n.header {\n grid-area: header;\n}\n\n.sidebar {\n grid-area: sidebar;\n}\n\n.content {\n grid-area: content;\n}\n\n.footer {\n grid-area: footer;\n}",
|
||||
"solution": "grid-template-areas:\n \"header header\"\n \"sidebar content\"\n \"footer footer\";",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "grid-template-areas",
|
||||
"message": "Use the 'grid-template-areas' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "header",
|
||||
"message": "Define a 'header' area",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "sidebar",
|
||||
"message": "Define a 'sidebar' area",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "content",
|
||||
"message": "Define a 'content' area",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "footer",
|
||||
"message": "Define a 'footer' area",
|
||||
"message": "Use the <kbd>grid-template-areas</kbd> property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
@@ -138,7 +84,7 @@
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "grid-template-areas:\\s*['\"]header\\s+header['\"]\\s*['\"]sidebar\\s+content['\"]\\s*['\"]footer\\s+footer['\"]",
|
||||
"message": "Create a layout with header spanning full width, sidebar and content in middle row, and footer spanning full width",
|
||||
"message": "Create areas: <kbd>\"header header\" \"sidebar content\" \"footer footer\"</kbd>",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
@@ -149,35 +95,20 @@
|
||||
"id": "grid-3",
|
||||
"title": "Spanning Grid Cells",
|
||||
"description": "Make grid items span multiple grid cells horizontally or vertically.",
|
||||
"task": "Make the featured item span 2 columns and 2 rows using grid-column and grid-row.",
|
||||
"task": "Add <kbd>grid-column: span 2</kbd> and <kbd>grid-row: span 2</kbd> to <kbd>.featured</kbd> to span 2x2 cells.",
|
||||
"previewHTML": "<div class='grid-container'><div class='item'>1</div><div class='item'>2</div><div class='item featured'>Featured</div><div class='item'>4</div><div class='item'>5</div><div class='item'>6</div><div class='item'>7</div><div class='item'>8</div><div class='item'>9</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .item { background-color: #9b59b6; color: white; padding: 1.25rem; text-align: center; font-weight: bold; } .featured { background-color: #e74c3c; }",
|
||||
"sandboxCSS": ".grid-container { border: 0.125rem dashed #ccc; padding: 1rem; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }",
|
||||
"codePrefix": "/* Make the featured item span 2x2 cells */\n",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "",
|
||||
"solution": ".featured {\n grid-column: span 2;\n grid-row: span 2;\n}",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": ".featured",
|
||||
"message": "Use the '.featured' class selector",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "grid-column",
|
||||
"message": "Use the 'grid-column' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "grid-row",
|
||||
"message": "Use the 'grid-row' property",
|
||||
"message": "Use the <kbd>.featured</kbd> class selector",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
@@ -185,7 +116,7 @@
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "grid-column:\\s*span\\s+2",
|
||||
"message": "Set grid-column to 'span 2'",
|
||||
"message": "Set <kbd>grid-column: span 2</kbd>",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
@@ -193,7 +124,7 @@
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "grid-row:\\s*span\\s+2",
|
||||
"message": "Set grid-row to 'span 2'",
|
||||
"message": "Set <kbd>grid-row: span 2</kbd>",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
@@ -203,60 +134,40 @@
|
||||
{
|
||||
"id": "grid-4",
|
||||
"title": "Automatic Grid Placement",
|
||||
"description": "Learn how to use auto-placement and auto-fit/auto-fill for responsive grid layouts.",
|
||||
"task": "Create a responsive grid with auto-fit that has at least 10rem wide columns that fill the available space.",
|
||||
"description": "Learn how to use auto-placement and <kbd>auto-fit</kbd>/<kbd>auto-fill</kbd> for responsive grid layouts.",
|
||||
"task": "Add <kbd>display: grid</kbd> and <kbd>grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr))</kbd> to <kbd>.responsive-grid</kbd>.",
|
||||
"previewHTML": "<div class='responsive-grid'><div class='card'>Card 1</div><div class='card'>Card 2</div><div class='card'>Card 3</div><div class='card'>Card 4</div><div class='card'>Card 5</div><div class='card'>Card 6</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .card { background-color: #3498db; color: white; padding: 1.25rem; text-align: center; font-weight: bold; height: 6rem; display: flex; align-items: center; justify-content: center; }",
|
||||
"sandboxCSS": ".responsive-grid { border: 0.125rem dashed #ccc; padding: 1rem; }",
|
||||
"codePrefix": "/* Create a responsive grid with auto-fit columns */\n",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "",
|
||||
"solution": ".responsive-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));\n}",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": ".responsive-grid",
|
||||
"message": "Use the '.responsive-grid' class selector",
|
||||
"message": "Use the <kbd>.responsive-grid</kbd> class selector",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "display",
|
||||
"message": "Use the 'display' property",
|
||||
"type": "property_value",
|
||||
"value": {
|
||||
"property": "display",
|
||||
"expected": "grid"
|
||||
},
|
||||
"message": "Set <kbd>display: grid</kbd>",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "grid-template-columns",
|
||||
"message": "Use the 'grid-template-columns' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "minmax",
|
||||
"message": "Use the 'minmax' function",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "auto-fit",
|
||||
"message": "Use 'auto-fit'",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
"exact": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "grid-template-columns:\\s*repeat\\(\\s*auto-fit\\s*,\\s*minmax\\(\\s*10rem\\s*,\\s*1fr\\s*\\)\\s*\\)",
|
||||
"message": "Set grid-template-columns to 'repeat(auto-fit, minmax(10rem, 1fr))'",
|
||||
"message": "Set <kbd>grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr))</kbd>",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
@@ -267,38 +178,23 @@
|
||||
"id": "grid-5",
|
||||
"title": "Grid Alignment",
|
||||
"description": "Control the alignment of grid items within their cells on both axes.",
|
||||
"task": "Center the grid items both horizontally and vertically within their grid cells.",
|
||||
"task": "Add <kbd>justify-items: center</kbd> and <kbd>align-items: center</kbd> to center items within their cells.",
|
||||
"previewHTML": "<div class='align-grid'><div class='item'>1</div><div class='item tall'>2</div><div class='item'>3</div><div class='item'>4</div><div class='item'>5</div><div class='item wide'>6</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .item { background-color: #9b59b6; color: white; padding: 1.25rem; text-align: center; font-weight: bold; width: 3rem; height: 3rem; } .tall { height: 6rem; } .wide { width: 6rem; }",
|
||||
"sandboxCSS": ".align-grid { border: 0.125rem dashed #ccc; padding: 1rem; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; height: 25rem; }",
|
||||
"codePrefix": "/* Center grid items both horizontally and vertically */\n.align-grid {\n /* Add alignment properties below */\n",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "justify-items: center;\n align-items: center;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "justify-items",
|
||||
"message": "Use the 'justify-items' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "align-items",
|
||||
"message": "Use the 'align-items' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": {
|
||||
"property": "justify-items",
|
||||
"expected": "center"
|
||||
},
|
||||
"message": "Set justify-items to 'center'",
|
||||
"message": "Set <kbd>justify-items: center</kbd>",
|
||||
"options": {
|
||||
"exact": true
|
||||
}
|
||||
@@ -309,7 +205,7 @@
|
||||
"property": "align-items",
|
||||
"expected": "center"
|
||||
},
|
||||
"message": "Set align-items to 'center'",
|
||||
"message": "Set <kbd>align-items: center</kbd>",
|
||||
"options": {
|
||||
"exact": true
|
||||
}
|
||||
@@ -319,47 +215,24 @@
|
||||
{
|
||||
"id": "grid-6",
|
||||
"title": "Overlapping Grid Items",
|
||||
"description": "Learn how to create overlapping layouts by using grid positioning and z-index.",
|
||||
"task": "Position the overlay element to cover the entire grid area and use z-index to place it above other items.",
|
||||
"description": "Learn how to create overlapping layouts by using grid positioning and <kbd>z-index</kbd>.",
|
||||
"task": "Add <kbd>grid-column: 1</kbd>, <kbd>grid-row: 1</kbd>, and <kbd>z-index: 1</kbd> to <kbd>.overlay</kbd> to position it above the base.",
|
||||
"previewHTML": "<div class='overlap-grid'><div class='base'>Base Content</div><div class='overlay'>Overlay</div></div>",
|
||||
"previewBaseCSS": "body { font-family: system-ui, -apple-system, sans-serif; padding: 1.25rem; } .overlap-grid { position: relative; height: 15rem; } .base { background-color: #3498db; color: white; padding: 1.25rem; display: flex; align-items: center; justify-content: center; font-weight: bold; } .overlay { background-color: rgba(231, 76, 60, 0.7); color: white; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 1.5rem; }",
|
||||
"sandboxCSS": ".overlap-grid { border: 0.125rem dashed #ccc; padding: 1rem; display: grid; grid-template-columns: 1fr; grid-template-rows: 1fr; }",
|
||||
"codePrefix": "/* Position the overlay to cover the entire grid */\n.base {\n grid-column: 1;\n grid-row: 1;\n}\n\n.overlay {\n /* Add your code below to position the overlay */\n",
|
||||
"initialCode": "",
|
||||
"codeSuffix": "\n}",
|
||||
"solution": "grid-column: 1;\n grid-row: 1;\n z-index: 1;",
|
||||
"previewContainer": "preview-area",
|
||||
"validations": [
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "grid-column",
|
||||
"message": "Use the 'grid-column' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "grid-row",
|
||||
"message": "Use the 'grid-row' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "contains",
|
||||
"value": "z-index",
|
||||
"message": "Use the 'z-index' property",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "property_value",
|
||||
"value": {
|
||||
"property": "grid-column",
|
||||
"expected": "1"
|
||||
},
|
||||
"message": "Set grid-column to '1'",
|
||||
"message": "Set <kbd>grid-column: 1</kbd>",
|
||||
"options": {
|
||||
"exact": true
|
||||
}
|
||||
@@ -370,7 +243,7 @@
|
||||
"property": "grid-row",
|
||||
"expected": "1"
|
||||
},
|
||||
"message": "Set grid-row to '1'",
|
||||
"message": "Set <kbd>grid-row: 1</kbd>",
|
||||
"options": {
|
||||
"exact": true
|
||||
}
|
||||
@@ -378,7 +251,7 @@
|
||||
{
|
||||
"type": "regex",
|
||||
"value": "z-index:\\s*[1-9]\\d*",
|
||||
"message": "Set z-index to a positive number",
|
||||
"message": "Set <kbd>z-index</kbd> to a positive number",
|
||||
"options": {
|
||||
"caseSensitive": false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user