feat: sync all flexbox translations to match English version

- Updated de, pl, es, ar, uk flexbox lessons to use identical structure
- All 6 lessons now match English: previewHTML, validations, solutions
- Only title, description, task, and message fields are translated
- Real-world examples: nav menus, headers, cards, toolbars

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
2026-01-14 12:07:35 +01:00
parent 0e16b76f3c
commit cc2faa5104
5 changed files with 271 additions and 432 deletions

View File

@@ -2,18 +2,18 @@
"$schema": "../../schemas/code-crispies-module-schema.json", "$schema": "../../schemas/code-crispies-module-schema.json",
"id": "flexbox", "id": "flexbox",
"title": "CSS Flexbox", "title": "CSS Flexbox",
"description": "Master the flexible box layout model for modern responsive designs", "description": "أتقن نموذج تخطيط الصندوق المرن للتصاميم المتجاوبة الحديثة",
"difficulty": "intermediate", "difficulty": "intermediate",
"lessons": [ "lessons": [
{ {
"id": "flexbox-1", "id": "flexbox-1",
"title": "Container", "title": "Container",
"description": "Learn how to create a flex container and understand the main and cross axes.", "description": "قبل flexbox، كانت حتى التخطيطات البسيطة تتطلب floats أو حيل التموضع أو تخطيطات الجداول. ثورة Flexbox (تخطيط الصندوق المرن) في CSS من خلال توفير نظام تخطيط أحادي البعد مصمم خصيصاً لتوزيع المساحة ومحاذاة المحتوى.<br><br><strong>كيف يعمل:</strong> عندما تضبط <kbd>display: flex</kbd> على عنصر، يصبح <em>حاوية flex</em>. أبناؤه المباشرون يصبحون تلقائياً <em>عناصر flex</em> تتدفق على طول المحور الرئيسي (أفقياً بشكل افتراضي). هذه الخاصية الواحدة تحول العناصر الكتلية المتراصة إلى صف أفقي.<br><br><strong>المحوران:</strong><br>• <em>المحور الرئيسي</em> الاتجاه الأساسي لتدفق العناصر (row = يسار→يمين)<br>• <em>المحور المتقاطع</em> عمودي على الرئيسي (row = أعلى→أسفل)<br><br><pre>.nav {\n display: flex;\n}</pre>",
"task": "Add <kbd>display: flex</kbd> to <kbd>.wrap</kbd> to create a flexbox layout.", "task": "قائمة التنقل هذه تتراص عمودياً. أضف <kbd>display: flex</kbd> لترتيب الروابط أفقياً.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>", "previewHTML": "<nav class=\"nav\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a><a href=\"#\">Contact</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "display: flex;", "solution": "display: flex;",
@@ -21,61 +21,41 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "display", "expected": "flex" },
"property": "display", "message": "اضبط <kbd>display: flex</kbd>"
"expected": "flex"
},
"message": "Set <kbd>display: flex</kbd>"
} }
] ]
}, },
{ {
"id": "flexbox-2", "id": "flexbox-2",
"title": "Direction & Wrap", "title": "Gap",
"description": "Control the direction and wrapping of flex items within a container.", "description": "خاصية <kbd>gap</kbd> تضيف تباعداً متسقاً بين عناصر flex بدون الحاجة إلى الهوامش. تُنشئ مساحة فقط بين العناصر، وليس على الحواف.",
"task": "Add <kbd>flex-direction: column</kbd> and <kbd>flex-wrap: wrap</kbd> to <kbd>.wrap</kbd>.", "task": "أضف <kbd>gap: 1rem</kbd> لتوزيع روابط التنقل بالتساوي.",
"previewHTML": "<div class='wrap'><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>", "previewHTML": "<nav class=\"nav\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a><a href=\"#\">Contact</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; height: 16rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "flex-direction: column;\n flex-wrap: wrap;", "solution": "gap: 1rem;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "gap", "expected": "1rem" },
"property": "flex-direction", "message": "اضبط <kbd>gap: 1rem</kbd>"
"expected": "column"
},
"message": "Set <kbd>flex-direction: column</kbd>",
"options": {
"exact": true
}
},
{
"type": "property_value",
"value": {
"property": "flex-wrap",
"expected": "wrap"
},
"message": "Set <kbd>flex-wrap: wrap</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-3", "id": "flexbox-3",
"title": "Justify Content", "title": "Justify Content",
"description": "Learn how to align flex items along the main axis of the flex container.", "description": "<kbd>justify-content</kbd> يوزع العناصر على طول المحور الرئيسي. القيم الشائعة:<br>• <kbd>flex-start</kbd> تجميع في البداية<br>• <kbd>flex-end</kbd> تجميع في النهاية<br>• <kbd>center</kbd> توسيط العناصر<br>• <kbd>space-between</kbd> مسافة متساوية بين العناصر<br>• <kbd>space-around</kbd> مسافة متساوية حول العناصر",
"task": "Add <kbd>justify-content: space-between</kbd> to <kbd>.wrap</kbd> to distribute the boxes evenly.", "task": "ادفع زر \"Login\" إلى اليمين بضبط <kbd>justify-content: space-between</kbd> على التنقل.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>", "previewHTML": "<nav class=\"nav\"><div class=\"links\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a></div><a href=\"#\" class=\"login\">Login</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "justify-content: space-between;", "solution": "justify-content: space-between;",
@@ -83,26 +63,20 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "justify-content", "expected": "space-between" },
"property": "justify-content", "message": "اضبط <kbd>justify-content: space-between</kbd>"
"expected": "space-between"
},
"message": "Set <kbd>justify-content: space-between</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-4", "id": "flexbox-4",
"title": "Align Items", "title": "Align Items",
"description": "Control how flex items are aligned along the cross axis of the flex container.", "description": "<kbd>align-items</kbd> يتحكم في المحاذاة على المحور المتقاطع (عمودياً عندما يكون flex-direction هو row). القيم تشمل:<br>• <kbd>stretch</kbd> تمديد للملء (افتراضي)<br>• <kbd>flex-start</kbd> محاذاة للأعلى<br>• <kbd>flex-end</kbd> محاذاة للأسفل<br>• <kbd>center</kbd> توسيط عمودي",
"task": "Add <kbd>align-items: center</kbd> to <kbd>.wrap</kbd> to vertically center the boxes.", "task": "الشعار وروابط التنقل لها ارتفاعات مختلفة. وسّطها عمودياً باستخدام <kbd>align-items: center</kbd>.",
"previewHTML": "<div class='wrap'><div class='box tall'>1</div><div class='box'>2</div><div class='box short'>3</div></div>", "previewHTML": "<header class=\"header\"><div class=\"logo\">ACME</div><nav><a href=\"#\">Products</a><a href=\"#\">Pricing</a><a href=\"#\">Docs</a></nav></header>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 10rem; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".header {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "align-items: center;", "solution": "align-items: center;",
@@ -110,62 +84,50 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "align-items", "expected": "center" },
"property": "align-items", "message": "اضبط <kbd>align-items: center</kbd>"
"expected": "center"
},
"message": "Set <kbd>align-items: center</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-5", "id": "flexbox-5",
"title": "Flex Grow", "title": "Flex Wrap",
"description": "The <kbd>flex</kbd> property controls how much an item grows relative to others.", "description": "بشكل افتراضي، تنضغط عناصر flex في سطر واحد. <kbd>flex-wrap: wrap</kbd> يسمح للعناصر بالتدفق إلى أسطر متعددة عندما تنفد المساحة.",
"task": "Add <kbd>flex: 2</kbd> to <kbd>.box2</kbd> to make it grow twice as wide.", "task": "هذه البطاقات تتجاوز الحاوية. أضف <kbd>flex-wrap: wrap</kbd> للسماح لها بالانتقال إلى صفوف جديدة.",
"previewHTML": "<div class='wrap'><div class='box box1'>1</div><div class='box box2'>2</div><div class='box box3'>3</div></div>", "previewHTML": "<div class=\"cards\"><article class=\"card\">Card 1</article><article class=\"card\">Card 2</article><article class=\"card\">Card 3</article><article class=\"card\">Card 4</article><article class=\"card\">Card 5</article><article class=\"card\">Card 6</article></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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".box2 {\n ", "codePrefix": ".cards {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "flex: 2;", "solution": "flex-wrap: wrap;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "flex-wrap", "expected": "wrap" },
"property": "flex", "message": "اضبط <kbd>flex-wrap: wrap</kbd>"
"expected": "2"
},
"message": "Set <kbd>flex: 2</kbd>"
} }
] ]
}, },
{ {
"id": "flexbox-6", "id": "flexbox-6",
"title": "Align Self", "title": "Flex Grow",
"description": "Use <kbd>align-self</kbd> to override alignment for a single flex item.", "description": "خاصية <kbd>flex</kbd> على العناصر تتحكم في كيفية نموها وانكماشها. <kbd>flex: 1</kbd> يجعل العنصر ينمو لملء المساحة المتاحة. عناصر متعددة مع <kbd>flex: 1</kbd> تتشارك المساحة بالتساوي.",
"task": "Add <kbd>align-self: flex-start</kbd> to <kbd>.middle</kbd> to move it to the top.", "task": "اجعل حقل البحث يتوسع لملء المساحة المتاحة بضبط <kbd>flex: 1</kbd> على <kbd>.search</kbd>.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box middle'>2</div><div class='box'>3</div></div>", "previewHTML": "<div class=\"toolbar\"><input class=\"search\" type=\"text\" placeholder=\"Search...\"><button class=\"btn\">Search</button><button class=\"btn\">Filters</button></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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 12rem; align-items: center; }", "sandboxCSS": "",
"codePrefix": ".middle {\n ", "codePrefix": ".search {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "align-self: flex-start;", "solution": "flex: 1;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "flex", "expected": "1" },
"property": "align-self", "message": "اضبط <kbd>flex: 1</kbd>"
"expected": "flex-start"
},
"message": "Set <kbd>align-self: flex-start</kbd>"
} }
] ]
} }

View File

@@ -7,13 +7,13 @@
"lessons": [ "lessons": [
{ {
"id": "flexbox-1", "id": "flexbox-1",
"title": "Flex Container", "title": "Container",
"description": "Flexbox ist ein eindimensionales Layout-System. Mit <kbd>display: flex</kbd> wird ein Element zum Flex-Container. Alle direkten Kinder werden automatisch zu Flex-Items und richten sich horizontal (Hauptachse) aus. Die Querachse verläuft senkrecht dazu.", "description": "Vor Flexbox erforderten selbst einfache Layouts Floats, Positionierungs-Hacks oder tabellenbasierte Layouts. Flexbox (Flexible Box Layout) revolutionierte CSS, indem es ein eindimensionales Layout-System speziell für Platzverteilung und Inhaltsausrichtung bereitstellte.<br><br><strong>So funktioniert es:</strong> Wenn du <kbd>display: flex</kbd> auf ein Element setzt, wird es zum <em>Flex-Container</em>. Seine direkten Kinder werden automatisch zu <em>Flex-Items</em>, die entlang einer Hauptachse fließen (standardmäßig horizontal). Diese eine Eigenschaft verwandelt gestapelte Block-Elemente in eine horizontale Reihe.<br><br><strong>Die zwei Achsen:</strong><br>• <em>Hauptachse</em> Die primäre Richtung, in der Items fließen (row = links→rechts)<br>• <em>Querachse</em> Senkrecht zur Hauptachse (row = oben→unten)<br><br><pre>.nav {\n display: flex;\n}</pre>",
"task": "Füge <kbd>display: flex</kbd> zu <kbd>.wrap</kbd> hinzu.", "task": "Dieses Navigationsmenü stapelt sich vertikal. Füge <kbd>display: flex</kbd> hinzu, um die Links horizontal anzuordnen.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>", "previewHTML": "<nav class=\"nav\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a><a href=\"#\">Contact</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "display: flex;", "solution": "display: flex;",
@@ -28,41 +28,34 @@
}, },
{ {
"id": "flexbox-2", "id": "flexbox-2",
"title": "Direction & Wrap", "title": "Gap",
"description": "<kbd>flex-direction</kbd> bestimmt die Hauptachse: <kbd>row</kbd> (horizontal, Standard) oder <kbd>column</kbd> (vertikal). Mit <kbd>flex-wrap: wrap</kbd> brechen Items in die nächste Zeile/Spalte um, wenn der Platz nicht reicht.", "description": "Die <kbd>gap</kbd>-Eigenschaft fügt konsistenten Abstand zwischen Flex-Items hinzu, ohne dass Margins nötig sind. Sie erzeugt nur Platz zwischen Items, nicht an den Rändern.",
"task": "Füge <kbd>flex-direction: column</kbd> und <kbd>flex-wrap: wrap</kbd> zu <kbd>.wrap</kbd> hinzu.", "task": "Füge <kbd>gap: 1rem</kbd> hinzu, um die Navigationslinks gleichmäßig zu verteilen.",
"previewHTML": "<div class='wrap'><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>", "previewHTML": "<nav class=\"nav\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a><a href=\"#\">Contact</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; height: 16rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "flex-direction: column;\n flex-wrap: wrap;", "solution": "gap: 1rem;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "flex-direction", "expected": "column" }, "value": { "property": "gap", "expected": "1rem" },
"message": "Setze <kbd>flex-direction: column</kbd>", "message": "Setze <kbd>gap: 1rem</kbd>"
"options": { "exact": true }
},
{
"type": "property_value",
"value": { "property": "flex-wrap", "expected": "wrap" },
"message": "Setze <kbd>flex-wrap: wrap</kbd>",
"options": { "exact": true }
} }
] ]
}, },
{ {
"id": "flexbox-3", "id": "flexbox-3",
"title": "Justify Content", "title": "Justify Content",
"description": "<kbd>justify-content</kbd> verteilt Items entlang der Hauptachse. Werte: <kbd>flex-start</kbd> (Anfang), <kbd>flex-end</kbd> (Ende), <kbd>center</kbd> (Mitte), <kbd>space-between</kbd> (gleichmäßig mit Abstand), <kbd>space-around</kbd> (gleichmäßig mit Rand).", "description": "<kbd>justify-content</kbd> verteilt Items entlang der Hauptachse. Häufige Werte:<br>• <kbd>flex-start</kbd> Items am Anfang<br>• <kbd>flex-end</kbd> Items am Ende<br>• <kbd>center</kbd> Items zentrieren<br>• <kbd>space-between</kbd> Gleicher Abstand zwischen Items<br>• <kbd>space-around</kbd> Gleicher Abstand um Items",
"task": "Füge <kbd>justify-content: space-between</kbd> zu <kbd>.wrap</kbd> hinzu.", "task": "Schiebe den \"Login\"-Button nach rechts, indem du <kbd>justify-content: space-between</kbd> auf die Navigation setzt.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>", "previewHTML": "<nav class=\"nav\"><div class=\"links\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a></div><a href=\"#\" class=\"login\">Login</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "justify-content: space-between;", "solution": "justify-content: space-between;",
@@ -71,20 +64,19 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "justify-content", "expected": "space-between" }, "value": { "property": "justify-content", "expected": "space-between" },
"message": "Setze <kbd>justify-content: space-between</kbd>", "message": "Setze <kbd>justify-content: space-between</kbd>"
"options": { "exact": true }
} }
] ]
}, },
{ {
"id": "flexbox-4", "id": "flexbox-4",
"title": "Align Items", "title": "Align Items",
"description": "<kbd>align-items</kbd> richtet Items entlang der Querachse aus (bei <kbd>row</kbd>: vertikal). Werte: <kbd>stretch</kbd> (Standard, füllt Höhe), <kbd>flex-start</kbd> (oben), <kbd>flex-end</kbd> (unten), <kbd>center</kbd> (Mitte), <kbd>baseline</kbd> (Textlinie).", "description": "<kbd>align-items</kbd> steuert die Ausrichtung auf der Querachse (vertikal bei flex-direction: row). Werte sind:<br>• <kbd>stretch</kbd> Ausdehnen zum Füllen (Standard)<br>• <kbd>flex-start</kbd> Oben ausrichten<br>• <kbd>flex-end</kbd> Unten ausrichten<br>• <kbd>center</kbd> Vertikal zentrieren",
"task": "Füge <kbd>align-items: center</kbd> zu <kbd>.wrap</kbd> hinzu.", "task": "Das Logo und die Nav-Links haben unterschiedliche Höhen. Zentriere sie vertikal mit <kbd>align-items: center</kbd>.",
"previewHTML": "<div class='wrap'><div class='box tall'>1</div><div class='box'>2</div><div class='box short'>3</div></div>", "previewHTML": "<header class=\"header\"><div class=\"logo\">ACME</div><nav><a href=\"#\">Products</a><a href=\"#\">Pricing</a><a href=\"#\">Docs</a></nav></header>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 10rem; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".header {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "align-items: center;", "solution": "align-items: center;",
@@ -93,50 +85,49 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "align-items", "expected": "center" }, "value": { "property": "align-items", "expected": "center" },
"message": "Setze <kbd>align-items: center</kbd>", "message": "Setze <kbd>align-items: center</kbd>"
"options": { "exact": true }
} }
] ]
}, },
{ {
"id": "flexbox-5", "id": "flexbox-5",
"title": "Flex Grow", "title": "Flex Wrap",
"description": "Die <kbd>flex</kbd>-Eigenschaft ist eine Kurzform für <kbd>flex-grow</kbd>, <kbd>flex-shrink</kbd> und <kbd>flex-basis</kbd>. Ein höherer Wert bedeutet, dass das Element mehr vom verfügbaren Platz einnimmt. <kbd>flex: 2</kbd> wächst doppelt so schnell wie <kbd>flex: 1</kbd>.", "description": "Standardmäßig quetschen sich Flex-Items in eine Zeile. <kbd>flex-wrap: wrap</kbd> erlaubt Items, auf mehrere Zeilen umzubrechen, wenn der Platz nicht reicht.",
"task": "Füge <kbd>flex: 2</kbd> zu <kbd>.box2</kbd> hinzu.", "task": "Diese Karten laufen über den Container hinaus. Füge <kbd>flex-wrap: wrap</kbd> hinzu, damit sie in neue Zeilen umbrechen können.",
"previewHTML": "<div class='wrap'><div class='box box1'>1</div><div class='box box2'>2</div><div class='box box3'>3</div></div>", "previewHTML": "<div class=\"cards\"><article class=\"card\">Card 1</article><article class=\"card\">Card 2</article><article class=\"card\">Card 3</article><article class=\"card\">Card 4</article><article class=\"card\">Card 5</article><article class=\"card\">Card 6</article></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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".box2 {\n ", "codePrefix": ".cards {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "flex: 2;", "solution": "flex-wrap: wrap;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "flex", "expected": "2" }, "value": { "property": "flex-wrap", "expected": "wrap" },
"message": "Setze <kbd>flex: 2</kbd>" "message": "Setze <kbd>flex-wrap: wrap</kbd>"
} }
] ]
}, },
{ {
"id": "flexbox-6", "id": "flexbox-6",
"title": "Align Self", "title": "Flex Grow",
"description": "<kbd>align-self</kbd> überschreibt <kbd>align-items</kbd> für ein einzelnes Element. So kannst du ein Item individuell auf der Querachse positionieren, während alle anderen Items ihrer Standard-Ausrichtung folgen.", "description": "Die <kbd>flex</kbd>-Eigenschaft auf Items steuert, wie sie wachsen und schrumpfen. <kbd>flex: 1</kbd> lässt ein Item wachsen, um verfügbaren Platz zu füllen. Mehrere Items mit <kbd>flex: 1</kbd> teilen sich den Platz gleichmäßig.",
"task": "Füge <kbd>align-self: flex-start</kbd> zu <kbd>.middle</kbd> hinzu.", "task": "Lass das Suchfeld den verfügbaren Platz ausfüllen, indem du <kbd>flex: 1</kbd> auf <kbd>.search</kbd> setzt.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box middle'>2</div><div class='box'>3</div></div>", "previewHTML": "<div class=\"toolbar\"><input class=\"search\" type=\"text\" placeholder=\"Search...\"><button class=\"btn\">Search</button><button class=\"btn\">Filters</button></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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 12rem; align-items: center; }", "sandboxCSS": "",
"codePrefix": ".middle {\n ", "codePrefix": ".search {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "align-self: flex-start;", "solution": "flex: 1;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "align-self", "expected": "flex-start" }, "value": { "property": "flex", "expected": "1" },
"message": "Setze <kbd>align-self: flex-start</kbd>" "message": "Setze <kbd>flex: 1</kbd>"
} }
] ]
} }

View File

@@ -2,18 +2,18 @@
"$schema": "../../schemas/code-crispies-module-schema.json", "$schema": "../../schemas/code-crispies-module-schema.json",
"id": "flexbox", "id": "flexbox",
"title": "CSS Flexbox", "title": "CSS Flexbox",
"description": "Master the flexible box layout model for modern responsive designs", "description": "Domina el modelo de caja flexible para diseños responsivos modernos",
"difficulty": "intermediate", "difficulty": "intermediate",
"lessons": [ "lessons": [
{ {
"id": "flexbox-1", "id": "flexbox-1",
"title": "Container", "title": "Container",
"description": "Learn how to create a flex container and understand the main and cross axes.", "description": "Antes de flexbox, incluso los diseños simples requerían floats, hacks de posicionamiento o diseños basados en tablas. Flexbox (Flexible Box Layout) revolucionó CSS al proporcionar un sistema de diseño unidimensional diseñado específicamente para distribuir espacio y alinear contenido.<br><br><strong>Cómo funciona:</strong> Cuando estableces <kbd>display: flex</kbd> en un elemento, se convierte en un <em>contenedor flex</em>. Sus hijos directos automáticamente se convierten en <em>elementos flex</em> que fluyen a lo largo de un eje principal (horizontal por defecto). Esta única propiedad transforma elementos de bloque apilados en una fila horizontal.<br><br><strong>Los dos ejes:</strong><br>• <em>Eje principal</em> La dirección primaria del flujo de elementos (row = izquierda→derecha)<br>• <em>Eje transversal</em> Perpendicular al principal (row = arriba→abajo)<br><br><pre>.nav {\n display: flex;\n}</pre>",
"task": "Add <kbd>display: flex</kbd> to <kbd>.wrap</kbd> to create a flexbox layout.", "task": "Este menú de navegación se apila verticalmente. Añade <kbd>display: flex</kbd> para organizar los enlaces horizontalmente.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>", "previewHTML": "<nav class=\"nav\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a><a href=\"#\">Contact</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "display: flex;", "solution": "display: flex;",
@@ -21,61 +21,41 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "display", "expected": "flex" },
"property": "display", "message": "Establece <kbd>display: flex</kbd>"
"expected": "flex"
},
"message": "Set <kbd>display: flex</kbd>"
} }
] ]
}, },
{ {
"id": "flexbox-2", "id": "flexbox-2",
"title": "Direction & Wrap", "title": "Gap",
"description": "Control the direction and wrapping of flex items within a container.", "description": "La propiedad <kbd>gap</kbd> añade espaciado consistente entre elementos flex sin necesidad de márgenes. Solo crea espacio entre elementos, no en los bordes.",
"task": "Add <kbd>flex-direction: column</kbd> and <kbd>flex-wrap: wrap</kbd> to <kbd>.wrap</kbd>.", "task": "Añade <kbd>gap: 1rem</kbd> para espaciar uniformemente los enlaces de navegación.",
"previewHTML": "<div class='wrap'><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>", "previewHTML": "<nav class=\"nav\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a><a href=\"#\">Contact</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; height: 16rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "flex-direction: column;\n flex-wrap: wrap;", "solution": "gap: 1rem;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "gap", "expected": "1rem" },
"property": "flex-direction", "message": "Establece <kbd>gap: 1rem</kbd>"
"expected": "column"
},
"message": "Set <kbd>flex-direction: column</kbd>",
"options": {
"exact": true
}
},
{
"type": "property_value",
"value": {
"property": "flex-wrap",
"expected": "wrap"
},
"message": "Set <kbd>flex-wrap: wrap</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-3", "id": "flexbox-3",
"title": "Justify Content", "title": "Justify Content",
"description": "Learn how to align flex items along the main axis of the flex container.", "description": "<kbd>justify-content</kbd> distribuye elementos a lo largo del eje principal. Valores comunes:<br>• <kbd>flex-start</kbd> agrupar al inicio<br>• <kbd>flex-end</kbd> agrupar al final<br>• <kbd>center</kbd> centrar elementos<br>• <kbd>space-between</kbd> espacio igual entre elementos<br>• <kbd>space-around</kbd> espacio igual alrededor de elementos",
"task": "Add <kbd>justify-content: space-between</kbd> to <kbd>.wrap</kbd> to distribute the boxes evenly.", "task": "Empuja el botón \"Login\" hacia la derecha estableciendo <kbd>justify-content: space-between</kbd> en la navegación.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>", "previewHTML": "<nav class=\"nav\"><div class=\"links\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a></div><a href=\"#\" class=\"login\">Login</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "justify-content: space-between;", "solution": "justify-content: space-between;",
@@ -83,26 +63,20 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "justify-content", "expected": "space-between" },
"property": "justify-content", "message": "Establece <kbd>justify-content: space-between</kbd>"
"expected": "space-between"
},
"message": "Set <kbd>justify-content: space-between</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-4", "id": "flexbox-4",
"title": "Align Items", "title": "Align Items",
"description": "Control how flex items are aligned along the cross axis of the flex container.", "description": "<kbd>align-items</kbd> controla la alineación en el eje transversal (vertical cuando flex-direction es row). Los valores incluyen:<br>• <kbd>stretch</kbd> estirar para llenar (por defecto)<br>• <kbd>flex-start</kbd> alinear arriba<br>• <kbd>flex-end</kbd> alinear abajo<br>• <kbd>center</kbd> centrar verticalmente",
"task": "Add <kbd>align-items: center</kbd> to <kbd>.wrap</kbd> to vertically center the boxes.", "task": "El logo y los enlaces de navegación tienen diferentes alturas. Céntralos verticalmente con <kbd>align-items: center</kbd>.",
"previewHTML": "<div class='wrap'><div class='box tall'>1</div><div class='box'>2</div><div class='box short'>3</div></div>", "previewHTML": "<header class=\"header\"><div class=\"logo\">ACME</div><nav><a href=\"#\">Products</a><a href=\"#\">Pricing</a><a href=\"#\">Docs</a></nav></header>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 10rem; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".header {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "align-items: center;", "solution": "align-items: center;",
@@ -110,62 +84,50 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "align-items", "expected": "center" },
"property": "align-items", "message": "Establece <kbd>align-items: center</kbd>"
"expected": "center"
},
"message": "Set <kbd>align-items: center</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-5", "id": "flexbox-5",
"title": "Flex Grow", "title": "Flex Wrap",
"description": "The <kbd>flex</kbd> property controls how much an item grows relative to others.", "description": "Por defecto, los elementos flex se comprimen en una línea. <kbd>flex-wrap: wrap</kbd> permite que los elementos fluyan a múltiples líneas cuando se quedan sin espacio.",
"task": "Add <kbd>flex: 2</kbd> to <kbd>.box2</kbd> to make it grow twice as wide.", "task": "Estas tarjetas desbordan el contenedor. Añade <kbd>flex-wrap: wrap</kbd> para permitir que pasen a nuevas filas.",
"previewHTML": "<div class='wrap'><div class='box box1'>1</div><div class='box box2'>2</div><div class='box box3'>3</div></div>", "previewHTML": "<div class=\"cards\"><article class=\"card\">Card 1</article><article class=\"card\">Card 2</article><article class=\"card\">Card 3</article><article class=\"card\">Card 4</article><article class=\"card\">Card 5</article><article class=\"card\">Card 6</article></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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".box2 {\n ", "codePrefix": ".cards {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "flex: 2;", "solution": "flex-wrap: wrap;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "flex-wrap", "expected": "wrap" },
"property": "flex", "message": "Establece <kbd>flex-wrap: wrap</kbd>"
"expected": "2"
},
"message": "Set <kbd>flex: 2</kbd>"
} }
] ]
}, },
{ {
"id": "flexbox-6", "id": "flexbox-6",
"title": "Align Self", "title": "Flex Grow",
"description": "Use <kbd>align-self</kbd> to override alignment for a single flex item.", "description": "La propiedad <kbd>flex</kbd> en los elementos controla cómo crecen y se encogen. <kbd>flex: 1</kbd> hace que un elemento crezca para llenar el espacio disponible. Múltiples elementos con <kbd>flex: 1</kbd> comparten el espacio equitativamente.",
"task": "Add <kbd>align-self: flex-start</kbd> to <kbd>.middle</kbd> to move it to the top.", "task": "Haz que el campo de búsqueda se expanda para llenar el espacio disponible estableciendo <kbd>flex: 1</kbd> en <kbd>.search</kbd>.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box middle'>2</div><div class='box'>3</div></div>", "previewHTML": "<div class=\"toolbar\"><input class=\"search\" type=\"text\" placeholder=\"Search...\"><button class=\"btn\">Search</button><button class=\"btn\">Filters</button></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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 12rem; align-items: center; }", "sandboxCSS": "",
"codePrefix": ".middle {\n ", "codePrefix": ".search {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "align-self: flex-start;", "solution": "flex: 1;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "flex", "expected": "1" },
"property": "align-self", "message": "Establece <kbd>flex: 1</kbd>"
"expected": "flex-start"
},
"message": "Set <kbd>align-self: flex-start</kbd>"
} }
] ]
} }

View File

@@ -2,18 +2,18 @@
"$schema": "../../schemas/code-crispies-module-schema.json", "$schema": "../../schemas/code-crispies-module-schema.json",
"id": "flexbox", "id": "flexbox",
"title": "CSS Flexbox", "title": "CSS Flexbox",
"description": "Master the flexible box layout model for modern responsive designs", "description": "Opanuj model elastycznego układu pudełkowego dla nowoczesnych responsywnych projektów",
"difficulty": "intermediate", "difficulty": "intermediate",
"lessons": [ "lessons": [
{ {
"id": "flexbox-1", "id": "flexbox-1",
"title": "Container", "title": "Container",
"description": "Learn how to create a flex container and understand the main and cross axes.", "description": "Przed flexboxem nawet proste układy wymagały floatów, hacków pozycjonowania lub układów tabelarycznych. Flexbox (Flexible Box Layout) zrewolucjonizował CSS, dostarczając jednowymiarowy system układu zaprojektowany specjalnie do dystrybucji przestrzeni i wyrównywania zawartości.<br><br><strong>Jak to działa:</strong> Gdy ustawisz <kbd>display: flex</kbd> na elemencie, staje się on <em>kontenerem flex</em>. Jego bezpośrednie dzieci automatycznie stają się <em>elementami flex</em>, które płyną wzdłuż osi głównej (domyślnie poziomej). Ta jedna właściwość przekształca ułożone elementy blokowe w poziomy rząd.<br><br><strong>Dwie osie:</strong><br>• <em>Oś główna</em> Główny kierunek przepływu elementów (row = lewo→prawo)<br>• <em>Oś poprzeczna</em> Prostopadła do głównej (row = góra→dół)<br><br><pre>.nav {\n display: flex;\n}</pre>",
"task": "Add <kbd>display: flex</kbd> to <kbd>.wrap</kbd> to create a flexbox layout.", "task": "To menu nawigacyjne układa się pionowo. Dodaj <kbd>display: flex</kbd>, aby ułożyć linki poziomo.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>", "previewHTML": "<nav class=\"nav\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a><a href=\"#\">Contact</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "display: flex;", "solution": "display: flex;",
@@ -21,61 +21,41 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "display", "expected": "flex" },
"property": "display", "message": "Ustaw <kbd>display: flex</kbd>"
"expected": "flex"
},
"message": "Set <kbd>display: flex</kbd>"
} }
] ]
}, },
{ {
"id": "flexbox-2", "id": "flexbox-2",
"title": "Direction & Wrap", "title": "Gap",
"description": "Control the direction and wrapping of flex items within a container.", "description": "Właściwość <kbd>gap</kbd> dodaje równomierne odstępy między elementami flex bez potrzeby używania marginesów. Tworzy przestrzeń tylko między elementami, nie na krawędziach.",
"task": "Add <kbd>flex-direction: column</kbd> and <kbd>flex-wrap: wrap</kbd> to <kbd>.wrap</kbd>.", "task": "Dodaj <kbd>gap: 1rem</kbd>, aby równomiernie rozmieścić linki nawigacyjne.",
"previewHTML": "<div class='wrap'><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>", "previewHTML": "<nav class=\"nav\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a><a href=\"#\">Contact</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; height: 16rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "flex-direction: column;\n flex-wrap: wrap;", "solution": "gap: 1rem;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "gap", "expected": "1rem" },
"property": "flex-direction", "message": "Ustaw <kbd>gap: 1rem</kbd>"
"expected": "column"
},
"message": "Set <kbd>flex-direction: column</kbd>",
"options": {
"exact": true
}
},
{
"type": "property_value",
"value": {
"property": "flex-wrap",
"expected": "wrap"
},
"message": "Set <kbd>flex-wrap: wrap</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-3", "id": "flexbox-3",
"title": "Justify Content", "title": "Justify Content",
"description": "Learn how to align flex items along the main axis of the flex container.", "description": "<kbd>justify-content</kbd> rozmieszcza elementy wzdłuż osi głównej. Popularne wartości:<br>• <kbd>flex-start</kbd> pakuj elementy na początku<br>• <kbd>flex-end</kbd> pakuj na końcu<br>• <kbd>center</kbd> wyśrodkuj elementy<br>• <kbd>space-between</kbd> równa przestrzeń między elementami<br>• <kbd>space-around</kbd> równa przestrzeń wokół elementów",
"task": "Add <kbd>justify-content: space-between</kbd> to <kbd>.wrap</kbd> to distribute the boxes evenly.", "task": "Przesuń przycisk \"Login\" na prawą stronę, ustawiając <kbd>justify-content: space-between</kbd> na nawigacji.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>", "previewHTML": "<nav class=\"nav\"><div class=\"links\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a></div><a href=\"#\" class=\"login\">Login</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "justify-content: space-between;", "solution": "justify-content: space-between;",
@@ -83,26 +63,20 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "justify-content", "expected": "space-between" },
"property": "justify-content", "message": "Ustaw <kbd>justify-content: space-between</kbd>"
"expected": "space-between"
},
"message": "Set <kbd>justify-content: space-between</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-4", "id": "flexbox-4",
"title": "Align Items", "title": "Align Items",
"description": "Control how flex items are aligned along the cross axis of the flex container.", "description": "<kbd>align-items</kbd> kontroluje wyrównanie na osi poprzecznej (pionowo gdy flex-direction to row). Wartości to:<br>• <kbd>stretch</kbd> rozciągnij do wypełnienia (domyślnie)<br>• <kbd>flex-start</kbd> wyrównaj do góry<br>• <kbd>flex-end</kbd> wyrównaj do dołu<br>• <kbd>center</kbd> wyśrodkuj pionowo",
"task": "Add <kbd>align-items: center</kbd> to <kbd>.wrap</kbd> to vertically center the boxes.", "task": "Logo i linki nawigacyjne mają różne wysokości. Wyśrodkuj je pionowo za pomocą <kbd>align-items: center</kbd>.",
"previewHTML": "<div class='wrap'><div class='box tall'>1</div><div class='box'>2</div><div class='box short'>3</div></div>", "previewHTML": "<header class=\"header\"><div class=\"logo\">ACME</div><nav><a href=\"#\">Products</a><a href=\"#\">Pricing</a><a href=\"#\">Docs</a></nav></header>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 10rem; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".header {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "align-items: center;", "solution": "align-items: center;",
@@ -110,62 +84,50 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "align-items", "expected": "center" },
"property": "align-items", "message": "Ustaw <kbd>align-items: center</kbd>"
"expected": "center"
},
"message": "Set <kbd>align-items: center</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-5", "id": "flexbox-5",
"title": "Flex Grow", "title": "Flex Wrap",
"description": "The <kbd>flex</kbd> property controls how much an item grows relative to others.", "description": "Domyślnie elementy flex ściskają się w jednej linii. <kbd>flex-wrap: wrap</kbd> pozwala elementom przenosić się na kolejne linie, gdy zabraknie miejsca.",
"task": "Add <kbd>flex: 2</kbd> to <kbd>.box2</kbd> to make it grow twice as wide.", "task": "Te karty wychodzą poza kontener. Dodaj <kbd>flex-wrap: wrap</kbd>, aby mogły przenosić się do nowych wierszy.",
"previewHTML": "<div class='wrap'><div class='box box1'>1</div><div class='box box2'>2</div><div class='box box3'>3</div></div>", "previewHTML": "<div class=\"cards\"><article class=\"card\">Card 1</article><article class=\"card\">Card 2</article><article class=\"card\">Card 3</article><article class=\"card\">Card 4</article><article class=\"card\">Card 5</article><article class=\"card\">Card 6</article></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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".box2 {\n ", "codePrefix": ".cards {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "flex: 2;", "solution": "flex-wrap: wrap;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "flex-wrap", "expected": "wrap" },
"property": "flex", "message": "Ustaw <kbd>flex-wrap: wrap</kbd>"
"expected": "2"
},
"message": "Set <kbd>flex: 2</kbd>"
} }
] ]
}, },
{ {
"id": "flexbox-6", "id": "flexbox-6",
"title": "Align Self", "title": "Flex Grow",
"description": "Use <kbd>align-self</kbd> to override alignment for a single flex item.", "description": "Właściwość <kbd>flex</kbd> na elementach kontroluje ich rozrastanie i kurczenie się. <kbd>flex: 1</kbd> sprawia, że element rozrasta się, aby wypełnić dostępną przestrzeń. Wiele elementów z <kbd>flex: 1</kbd> dzieli przestrzeń równomiernie.",
"task": "Add <kbd>align-self: flex-start</kbd> to <kbd>.middle</kbd> to move it to the top.", "task": "Spraw, aby pole wyszukiwania rozszerzyło się i wypełniło dostępną przestrzeń, ustawiając <kbd>flex: 1</kbd> na <kbd>.search</kbd>.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box middle'>2</div><div class='box'>3</div></div>", "previewHTML": "<div class=\"toolbar\"><input class=\"search\" type=\"text\" placeholder=\"Search...\"><button class=\"btn\">Search</button><button class=\"btn\">Filters</button></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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 12rem; align-items: center; }", "sandboxCSS": "",
"codePrefix": ".middle {\n ", "codePrefix": ".search {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "align-self: flex-start;", "solution": "flex: 1;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "flex", "expected": "1" },
"property": "align-self", "message": "Ustaw <kbd>flex: 1</kbd>"
"expected": "flex-start"
},
"message": "Set <kbd>align-self: flex-start</kbd>"
} }
] ]
} }

View File

@@ -2,18 +2,18 @@
"$schema": "../../schemas/code-crispies-module-schema.json", "$schema": "../../schemas/code-crispies-module-schema.json",
"id": "flexbox", "id": "flexbox",
"title": "CSS Flexbox", "title": "CSS Flexbox",
"description": "Master the flexible box layout model for modern responsive designs", "description": "Опануйте модель гнучкого блочного макету для сучасних адаптивних дизайнів",
"difficulty": "intermediate", "difficulty": "intermediate",
"lessons": [ "lessons": [
{ {
"id": "flexbox-1", "id": "flexbox-1",
"title": "Container", "title": "Container",
"description": "Learn how to create a flex container and understand the main and cross axes.", "description": "До flexbox навіть прості макети вимагали floats, хаків позиціонування або табличних макетів. Flexbox (Flexible Box Layout) революціонізував CSS, надавши одновимірну систему макетування, спеціально розроблену для розподілу простору та вирівнювання вмісту.<br><br><strong>Як це працює:</strong> Коли ви встановлюєте <kbd>display: flex</kbd> на елемент, він стає <em>flex-контейнером</em>. Його прямі нащадки автоматично стають <em>flex-елементами</em>, що розташовуються вздовж головної осі (горизонтально за замовчуванням). Ця одна властивість перетворює вкладені блокові елементи в горизонтальний ряд.<br><br><strong>Дві осі:</strong><br>• <em>Головна вісь</em> Основний напрямок потоку елементів (row = зліва→направо)<br>• <em>Поперечна вісь</em> Перпендикулярна до головної (row = зверху→вниз)<br><br><pre>.nav {\n display: flex;\n}</pre>",
"task": "Add <kbd>display: flex</kbd> to <kbd>.wrap</kbd> to create a flexbox layout.", "task": "Це навігаційне меню розташовується вертикально. Додайте <kbd>display: flex</kbd>, щоб розташувати посилання горизонтально.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>", "previewHTML": "<nav class=\"nav\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a><a href=\"#\">Contact</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "display: flex;", "solution": "display: flex;",
@@ -21,61 +21,41 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "display", "expected": "flex" },
"property": "display", "message": "Встановіть <kbd>display: flex</kbd>"
"expected": "flex"
},
"message": "Set <kbd>display: flex</kbd>"
} }
] ]
}, },
{ {
"id": "flexbox-2", "id": "flexbox-2",
"title": "Direction & Wrap", "title": "Gap",
"description": "Control the direction and wrapping of flex items within a container.", "description": "Властивість <kbd>gap</kbd> додає послідовний відступ між flex-елементами без потреби у відступах (margins). Вона створює простір лише між елементами, а не по краях.",
"task": "Add <kbd>flex-direction: column</kbd> and <kbd>flex-wrap: wrap</kbd> to <kbd>.wrap</kbd>.", "task": "Додайте <kbd>gap: 1rem</kbd>, щоб рівномірно розташувати навігаційні посилання.",
"previewHTML": "<div class='wrap'><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>", "previewHTML": "<nav class=\"nav\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a><a href=\"#\">Contact</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; height: 16rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "flex-direction: column;\n flex-wrap: wrap;", "solution": "gap: 1rem;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "gap", "expected": "1rem" },
"property": "flex-direction", "message": "Встановіть <kbd>gap: 1rem</kbd>"
"expected": "column"
},
"message": "Set <kbd>flex-direction: column</kbd>",
"options": {
"exact": true
}
},
{
"type": "property_value",
"value": {
"property": "flex-wrap",
"expected": "wrap"
},
"message": "Set <kbd>flex-wrap: wrap</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-3", "id": "flexbox-3",
"title": "Justify Content", "title": "Justify Content",
"description": "Learn how to align flex items along the main axis of the flex container.", "description": "<kbd>justify-content</kbd> розподіляє елементи вздовж головної осі. Поширені значення:<br>• <kbd>flex-start</kbd> групувати на початку<br>• <kbd>flex-end</kbd> групувати в кінці<br>• <kbd>center</kbd> центрувати елементи<br>• <kbd>space-between</kbd> рівний простір між елементами<br>• <kbd>space-around</kbd> рівний простір навколо елементів",
"task": "Add <kbd>justify-content: space-between</kbd> to <kbd>.wrap</kbd> to distribute the boxes evenly.", "task": "Перемістіть кнопку \"Login\" праворуч, встановивши <kbd>justify-content: space-between</kbd> на навігації.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box'>2</div><div class='box'>3</div></div>", "previewHTML": "<nav class=\"nav\"><div class=\"links\"><a href=\"#\">Home</a><a href=\"#\">Products</a><a href=\"#\">About</a></div><a href=\"#\" class=\"login\">Login</a></nav>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".nav {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "justify-content: space-between;", "solution": "justify-content: space-between;",
@@ -83,26 +63,20 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "justify-content", "expected": "space-between" },
"property": "justify-content", "message": "Встановіть <kbd>justify-content: space-between</kbd>"
"expected": "space-between"
},
"message": "Set <kbd>justify-content: space-between</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-4", "id": "flexbox-4",
"title": "Align Items", "title": "Align Items",
"description": "Control how flex items are aligned along the cross axis of the flex container.", "description": "<kbd>align-items</kbd> керує вирівнюванням по поперечній осі (вертикально, коли flex-direction це row). Значення включають:<br>• <kbd>stretch</kbd> розтягнути для заповнення (за замовчуванням)<br>• <kbd>flex-start</kbd> вирівняти вгору<br>• <kbd>flex-end</kbd> вирівняти вниз<br>• <kbd>center</kbd> центрувати вертикально",
"task": "Add <kbd>align-items: center</kbd> to <kbd>.wrap</kbd> to vertically center the boxes.", "task": "Логотип та навігаційні посилання мають різну висоту. Відцентруйте їх вертикально за допомогою <kbd>align-items: center</kbd>.",
"previewHTML": "<div class='wrap'><div class='box tall'>1</div><div class='box'>2</div><div class='box short'>3</div></div>", "previewHTML": "<header class=\"header\"><div class=\"logo\">ACME</div><nav><a href=\"#\">Products</a><a href=\"#\">Pricing</a><a href=\"#\">Docs</a></nav></header>",
"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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 10rem; }", "sandboxCSS": "",
"codePrefix": ".wrap {\n ", "codePrefix": ".header {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "align-items: center;", "solution": "align-items: center;",
@@ -110,62 +84,50 @@
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "align-items", "expected": "center" },
"property": "align-items", "message": "Встановіть <kbd>align-items: center</kbd>"
"expected": "center"
},
"message": "Set <kbd>align-items: center</kbd>",
"options": {
"exact": true
}
} }
] ]
}, },
{ {
"id": "flexbox-5", "id": "flexbox-5",
"title": "Flex Grow", "title": "Flex Wrap",
"description": "The <kbd>flex</kbd> property controls how much an item grows relative to others.", "description": "За замовчуванням flex-елементи стискаються в один рядок. <kbd>flex-wrap: wrap</kbd> дозволяє елементам переходити на кілька рядків, коли місця недостатньо.",
"task": "Add <kbd>flex: 2</kbd> to <kbd>.box2</kbd> to make it grow twice as wide.", "task": "Ці картки виходять за межі контейнера. Додайте <kbd>flex-wrap: wrap</kbd>, щоб дозволити їм переходити на нові рядки.",
"previewHTML": "<div class='wrap'><div class='box box1'>1</div><div class='box box2'>2</div><div class='box box3'>3</div></div>", "previewHTML": "<div class=\"cards\"><article class=\"card\">Card 1</article><article class=\"card\">Card 2</article><article class=\"card\">Card 3</article><article class=\"card\">Card 4</article><article class=\"card\">Card 5</article><article class=\"card\">Card 6</article></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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; }", "sandboxCSS": "",
"codePrefix": ".box2 {\n ", "codePrefix": ".cards {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "flex: 2;", "solution": "flex-wrap: wrap;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "flex-wrap", "expected": "wrap" },
"property": "flex", "message": "Встановіть <kbd>flex-wrap: wrap</kbd>"
"expected": "2"
},
"message": "Set <kbd>flex: 2</kbd>"
} }
] ]
}, },
{ {
"id": "flexbox-6", "id": "flexbox-6",
"title": "Align Self", "title": "Flex Grow",
"description": "Use <kbd>align-self</kbd> to override alignment for a single flex item.", "description": "Властивість <kbd>flex</kbd> на елементах керує тим, як вони ростуть і зменшуються. <kbd>flex: 1</kbd> змушує елемент рости, щоб заповнити доступний простір. Кілька елементів з <kbd>flex: 1</kbd> ділять простір порівну.",
"task": "Add <kbd>align-self: flex-start</kbd> to <kbd>.middle</kbd> to move it to the top.", "task": "Зробіть так, щоб поле пошуку розширилось і заповнило доступний простір, встановивши <kbd>flex: 1</kbd> на <kbd>.search</kbd>.",
"previewHTML": "<div class='wrap'><div class='box'>1</div><div class='box middle'>2</div><div class='box'>3</div></div>", "previewHTML": "<div class=\"toolbar\"><input class=\"search\" type=\"text\" placeholder=\"Search...\"><button class=\"btn\">Search</button><button class=\"btn\">Filters</button></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; }", "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": ".wrap { border: 2px dashed #aaa; padding: 1rem; display: flex; height: 12rem; align-items: center; }", "sandboxCSS": "",
"codePrefix": ".middle {\n ", "codePrefix": ".search {\n ",
"initialCode": "", "initialCode": "",
"codeSuffix": "\n}", "codeSuffix": "\n}",
"solution": "align-self: flex-start;", "solution": "flex: 1;",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ {
"type": "property_value", "type": "property_value",
"value": { "value": { "property": "flex", "expected": "1" },
"property": "align-self", "message": "Встановіть <kbd>flex: 1</kbd>"
"expected": "flex-start"
},
"message": "Set <kbd>align-self: flex-start</kbd>"
} }
] ]
} }