Files
code-crispies/lessons/es/flexbox.json
Michael Czechowski c560676544 feat: implement #4 — replace answer-revealing validation messages with pedagogical hints
Rewrite ~120 validation error messages across 17 English lesson modules
and their localized variants (ar, de, es, pl, uk) to use concept questions,
property hints, and directional nudges instead of revealing the exact
CSS property-value answers.

Priority modules (flexbox, box-model, colors, positioning) fully rewritten.
All remaining CSS modules updated. Only message strings changed — no
validation logic modifications.
2026-03-28 19:40:28 +01:00

136 lines
9.0 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"$schema": "../../schemas/code-crispies-module-schema.json",
"id": "flexbox",
"title": "CSS Flexbox",
"description": "Domina el modelo de caja flexible para diseños responsivos modernos",
"difficulty": "intermediate",
"lessons": [
{
"id": "flexbox-1",
"title": "Container",
"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": "Este menú de navegación se apila verticalmente. Añade <kbd>display: flex</kbd> para organizar los enlaces horizontalmente.",
"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; 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": "",
"codePrefix": ".nav {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "display: flex;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
"value": { "property": "display", "expected": "flex" },
"message": "¿Qué valor de display convierte un elemento en un contenedor de caja flexible?"
}
]
},
{
"id": "flexbox-2",
"title": "Gap",
"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": "Añade <kbd>gap: 1rem</kbd> para espaciar uniformemente los enlaces de navegación.",
"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; 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": "",
"codePrefix": ".nav {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "gap: 1rem;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
"value": { "property": "gap", "expected": "1rem" },
"message": "¿Qué propiedad crea espaciado entre elementos flex sin usar márgenes?"
}
]
},
{
"id": "flexbox-3",
"title": "Justify Content",
"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": "Empuja el botón \"Login\" hacia la derecha estableciendo <kbd>justify-content: space-between</kbd> en la navegación.",
"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; 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": "",
"codePrefix": ".nav {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "justify-content: space-between;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
"value": { "property": "justify-content", "expected": "space-between" },
"message": "¿Qué valor de <kbd>justify-content</kbd> empuja el primer y último elemento a los extremos opuestos?"
}
]
},
{
"id": "flexbox-4",
"title": "Align Items",
"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": "El logo y los enlaces de navegación tienen diferentes alturas. Céntralos verticalmente con <kbd>align-items: center</kbd>.",
"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; 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": "",
"codePrefix": ".header {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "align-items: center;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
"value": { "property": "align-items", "expected": "center" },
"message": "¿Qué propiedad alinea los elementos flex a lo largo del eje transversal?"
}
]
},
{
"id": "flexbox-5",
"title": "Flex Wrap",
"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": "Estas tarjetas desbordan el contenedor. Añade <kbd>flex-wrap: wrap</kbd> para permitir que pasen a nuevas filas.",
"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; 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": "",
"codePrefix": ".cards {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "flex-wrap: wrap;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
"value": { "property": "flex-wrap", "expected": "wrap" },
"message": "¿Qué propiedad permite que los elementos flex fluyan a múltiples líneas?"
}
]
},
{
"id": "flexbox-6",
"title": "Flex Grow",
"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": "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=\"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; } .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": "",
"codePrefix": ".search {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "flex: 1;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
"value": { "property": "flex", "expected": "1" },
"message": "¿Qué propiedad hace que un elemento flex crezca para llenar el espacio restante?"
}
]
}
]
}