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.
This commit is contained in:
2026-03-28 19:40:28 +01:00
parent 782e87705c
commit c560676544
50 changed files with 434 additions and 403 deletions

View File

@@ -22,7 +22,7 @@
{
"type": "property_value",
"value": { "property": "color", "expected": "coral" },
"message": "أضف <kbd>color: coral;</kbd>"
"message": "ما الخاصية التي تتحكم في لون النص؟"
}
]
},
@@ -43,12 +43,12 @@
{
"type": "property_value",
"value": { "property": "background", "expected": "lavender" },
"message": "أضف <kbd>background: lavender;</kbd>"
"message": "تحقق من خاصية <kbd>background</kbd>"
},
{
"type": "property_value",
"value": { "property": "padding", "expected": "1rem" },
"message": "أضف <kbd>padding: 1rem;</kbd>"
"message": "البطاقة تحتاج إلى مساحة داخل حوافها"
}
]
},
@@ -74,7 +74,7 @@
{
"type": "property_value",
"value": { "property": "color", "expected": "steelblue" },
"message": "اضبط <kbd>color: steelblue</kbd>"
"message": "ما الخاصية التي تغيّر لون النص؟"
}
]
},
@@ -100,7 +100,7 @@
{
"type": "property_value",
"value": { "property": "color", "expected": "coral" },
"message": "اضبط <kbd>color: coral</kbd>"
"message": "ما القيمة التي تعطي لوناً دافئاً برتقالياً محمراً؟"
}
]
},
@@ -126,7 +126,7 @@
{
"type": "property_value",
"value": { "property": "background", "expected": "tomato" },
"message": "اضبط <kbd>background: tomato</kbd>"
"message": "الشارة تحتاج إلى خلفية حمراء زاهية"
}
]
},
@@ -152,7 +152,7 @@
{
"type": "property_value",
"value": { "property": "background", "expected": "steelblue" },
"message": "اضبط <kbd>background: steelblue</kbd>"
"message": "ما الخاصية التي تضبط لون تعبئة الزر؟"
}
]
},
@@ -178,7 +178,7 @@
{
"type": "property_value",
"value": { "property": "text-decoration", "expected": "none" },
"message": "اضبط <kbd>text-decoration: none</kbd>"
"message": "ما الخاصية التي تتحكم في الخط أسفل الروابط؟"
}
]
},
@@ -199,7 +199,7 @@
{
"type": "property_value",
"value": { "property": "color", "expected": "steelblue" },
"message": "اضبط <kbd>color: steelblue</kbd>"
"message": "تحقق من خاصية <kbd>color</kbd>"
}
]
},
@@ -225,7 +225,7 @@
{
"type": "property_value",
"value": { "property": "color", "expected": "white" },
"message": "اضبط <kbd>color: white</kbd>"
"message": "الروابط تحتاج إلى أن تبرز على الخلفية الزرقاء"
}
]
},
@@ -251,7 +251,7 @@
{
"type": "property_value",
"value": { "property": "font-size", "expected": "0.9rem" },
"message": "اضبط <kbd>font-size: 0.9rem</kbd>"
"message": "تحقق من خاصية <kbd>font-size</kbd> — النص يجب أن يكون أصغر قليلاً"
}
]
}

View File

@@ -22,7 +22,7 @@
{
"type": "property_value",
"value": { "property": "padding", "expected": "1rem" },
"message": "اضبط <kbd>padding: 1rem</kbd>"
"message": "ما الخاصية التي تضيف مساحة بين محتوى العنصر وحدوده؟"
}
]
},
@@ -43,7 +43,7 @@
{
"type": "regex",
"value": "border-left:\\s*4px\\s+solid\\s+steelblue",
"message": "اضبط <kbd>border-left: 4px solid steelblue</kbd>",
"message": "استخدم اختصار <kbd>border-left</kbd> مع قيم العرض والنمط واللون",
"options": { "caseSensitive": false }
}
]
@@ -65,7 +65,7 @@
{
"type": "property_value",
"value": { "property": "margin-bottom", "expected": "1rem" },
"message": "اضبط <kbd>margin-bottom: 1rem</kbd>"
"message": "ما الخاصية التي تُنشئ مساحة أسفل العنصر وتدفع الجيران بعيداً؟"
}
]
},
@@ -86,7 +86,7 @@
{
"type": "property_value",
"value": { "property": "box-sizing", "expected": "border-box" },
"message": "اضبط <kbd>box-sizing: border-box</kbd>"
"message": "ما قيمة <kbd>box-sizing</kbd> التي تشمل الحشو والحدود في العرض الإجمالي للعنصر؟"
}
]
},
@@ -107,7 +107,7 @@
{
"type": "regex",
"value": "padding:\\s*8px\\s+1rem",
"message": "اضبط <kbd>padding: 8px 1rem</kbd>",
"message": "استخدم اختصار <kbd>padding</kbd> بقيمتين: عمودي ثم أفقي",
"options": { "caseSensitive": false }
}
]
@@ -129,7 +129,7 @@
{
"type": "regex",
"value": "margin:\\s*0\\s+auto",
"message": "اضبط <kbd>margin: 0 auto</kbd>",
"message": "استخدم <kbd>margin</kbd> مع كلمة مفتاحية تحسب تلقائياً مسافات متساوية يميناً ويساراً",
"options": { "caseSensitive": false }
}
]
@@ -151,7 +151,7 @@
{
"type": "property_value",
"value": { "property": "border-radius", "expected": "50%" },
"message": "اضبط <kbd>border-radius: 50%</kbd>"
"message": "ما نسبة <kbd>border-radius</kbd> التي تُنشئ دائرة كاملة من عنصر مربع؟"
}
]
},
@@ -172,18 +172,18 @@
{
"type": "property_value",
"value": { "property": "padding", "expected": "1rem" },
"message": "اضبط <kbd>padding: 1rem</kbd>"
"message": "أضف مساحة داخلية لبطاقة الإشعار"
},
{
"type": "regex",
"value": "border-left:\\s*4px\\s+solid\\s+coral",
"message": "اضبط <kbd>border-left: 4px solid coral</kbd>",
"message": "أضف لمسة حدود يسارية باستخدام اختصار <kbd>border-left</kbd>",
"options": { "caseSensitive": false }
},
{
"type": "property_value",
"value": { "property": "border-radius", "expected": "4px" },
"message": "اضبط <kbd>border-radius: 4px</kbd>"
"message": "دوّر الزوايا قليلاً باستخدام <kbd>border-radius</kbd>"
}
]
}

View File

@@ -22,7 +22,7 @@
{
"type": "property_value",
"value": { "property": "max-width", "expected": "40rem" },
"message": "اضبط <kbd>max-width: 40rem</kbd>"
"message": "ما الخاصية التي تحدّ من عرض العنصر؟ جرّب قيمة بوحدة <kbd>rem</kbd> لطول سطر مقروء."
}
]
},
@@ -43,13 +43,13 @@
{
"type": "contains",
"value": "--brand",
"message": "عرّف المتغير <kbd>--brand</kbd>",
"message": "عرّف متغير <kbd>--brand</kbd>",
"options": { "caseSensitive": false }
},
{
"type": "contains",
"value": "steelblue",
"message": "اضبط القيمة على <kbd>steelblue</kbd>",
"message": "اضبط القيمة إلى <kbd>steelblue</kbd>",
"options": { "caseSensitive": false }
}
]
@@ -71,7 +71,7 @@
{
"type": "regex",
"value": "width:\\s*calc\\(\\s*100%\\s*-\\s*200px\\s*\\)",
"message": "اضبط <kbd>width: calc(100% - 200px)</kbd>",
"message": "استخدم <kbd>calc()</kbd> لطرح عرض الشريط الجانبي الثابت من عرض الحاوية الكامل.",
"options": { "caseSensitive": false }
}
]
@@ -93,7 +93,7 @@
{
"type": "property_value",
"value": { "property": "min-height", "expected": "100vh" },
"message": "اضبط <kbd>min-height: 100vh</kbd>"
"message": "ما الخاصية التي تضمن حداً أدنى للارتفاع؟ استخدم وحدة viewport لتغطية الشاشة بالكامل."
}
]
}

View File

@@ -28,7 +28,7 @@
{
"type": "regex",
"value": "transition:\\s*background-color\\s*0\\.3s",
"message": "اضبط <kbd>transition: background-color 0.3s</kbd>",
"message": "حدد أي خاصية تريد تحريكها وكم من الوقت يجب أن تستغرق.",
"options": { "caseSensitive": false }
}
]
@@ -56,7 +56,7 @@
{
"type": "property_value",
"value": { "property": "transition-timing-function", "expected": "ease-in-out" },
"message": "اضبط التوقيت على <kbd>ease-in-out</kbd>"
"message": "ما كلمة التسهيل التي تبدأ بطيئة، تتسارع، ثم تبطئ مرة أخرى؟"
}
]
},
@@ -95,7 +95,7 @@
{
"type": "regex",
"value": "animation:.*bounce.*1s.*infinite",
"message": "طبّق <kbd>animation: bounce 1s infinite</kbd>",
"message": "استخدم اختصار <kbd>animation</kbd>: الاسم، المدة، وعدد التكرار.",
"options": { "caseSensitive": false }
}
]
@@ -117,27 +117,27 @@
{
"type": "property_value",
"value": { "property": "animation-name", "expected": "pulse" },
"message": "اضبط <kbd>animation-name: pulse</kbd>"
"message": "ما الخاصية التي تربط العنصر بقاعدة <kbd>@keyframes</kbd> مسماة؟"
},
{
"type": "property_value",
"value": { "property": "animation-duration", "expected": "2s" },
"message": "اضبط <kbd>animation-duration: 2s</kbd>"
"message": "كم يجب أن تستغرق دورة كاملة من الحركة؟"
},
{
"type": "property_value",
"value": { "property": "animation-delay", "expected": "1s" },
"message": "اضبط <kbd>animation-delay: 1s</kbd>"
"message": "ما الخاصية التي تجعل الحركة تنتظر قبل أن تبدأ؟"
},
{
"type": "property_value",
"value": { "property": "animation-iteration-count", "expected": "2" },
"message": "اضبط <kbd>animation-iteration-count: 2</kbd>"
"message": "ما الخاصية التي تتحكم في عدد مرات تكرار الحركة؟"
},
{
"type": "property_value",
"value": { "property": "animation-fill-mode", "expected": "forwards" },
"message": "اضبط <kbd>animation-fill-mode: forwards</kbd>"
"message": "ما الخاصية التي تُبقي العنصر بتنسيق حالته النهائية بعد انتهاء الحركة؟"
}
]
}

View File

@@ -22,7 +22,7 @@
{
"type": "regex",
"value": "@media\\s*\\(max-width:\\s*600px\\)",
"message": "استخدم <kbd>@media (max-width: 600px)</kbd>",
"message": "ابدأ بقاعدة <kbd>@media</kbd> — ما الشرط الذي يستهدف الشاشات بعرض 600px أو أقل؟",
"options": { "caseSensitive": false }
},
{
@@ -34,7 +34,7 @@
{
"type": "property_value",
"value": { "property": "background", "expected": "lightcoral" },
"message": "اضبط <kbd>background: lightcoral</kbd>",
"message": "ما الخاصية التي تغيّر لون خلفية العنصر؟",
"options": { "exact": false }
}
]
@@ -53,7 +53,11 @@
"solution": " font-size: 5vw;",
"previewContainer": "preview-area",
"validations": [
{ "type": "property_value", "value": { "property": "font-size", "expected": "5vw" }, "message": "اضبط <kbd>font-size: 5vw</kbd>" }
{
"type": "property_value",
"value": { "property": "font-size", "expected": "5vw" },
"message": "ما وحدة CSS التي تتناسب مع عرض viewport؟"
}
]
},
{
@@ -73,18 +77,18 @@
{
"type": "property_value",
"value": { "property": "display", "expected": "grid" },
"message": "اضبط <kbd>display: grid</kbd>"
"message": "ما وضع العرض الذي يتيح لك تعريف صفوف وأعمدة؟"
},
{
"type": "regex",
"value": "repeat\\(auto-fit,\\s*minmax\\(200px,\\s*1fr\\)\\)",
"message": "استخدم <kbd>repeat(auto-fit, minmax(200px, 1fr))</kbd>",
"message": "جرّب <kbd>repeat()</kbd> مع <kbd>auto-fit</kbd> و <kbd>minmax()</kbd> — ما الحد الأدنى والأقصى للحجم لإنشاء أعمدة مرنة؟",
"options": { "caseSensitive": false }
},
{
"type": "property_value",
"value": { "property": "gap", "expected": "1rem" },
"message": "اضبط <kbd>gap: 1rem</kbd>"
"message": "ما الخاصية التي تضيف مساحة بين عناصر الشبكة؟"
}
]
},
@@ -105,7 +109,7 @@
{
"type": "regex",
"value": "@media\\s*\\(min-width:\\s*768px\\)",
"message": "استخدم <kbd>@media (min-width: 768px)</kbd>",
"message": "ما شرط <kbd>@media</kbd> الذي يُطبّق الأنماط عندما يكون عرض viewport على الأقل 768px؟",
"options": { "caseSensitive": false }
},
{
@@ -117,7 +121,7 @@
{
"type": "property_value",
"value": { "property": "width", "expected": "250px" },
"message": "اضبط <kbd>width: 250px</kbd>",
"message": "ما الخاصية التي تتحكم في عرض الشريط الجانبي على الشاشات الكبيرة؟",
"options": { "exact": false }
}
]

View File

@@ -22,7 +22,7 @@
{
"type": "property_value",
"value": { "property": "display", "expected": "flex" },
"message": "اضبط <kbd>display: flex</kbd>"
"message": "ما قيمة display التي تحوّل العنصر إلى حاوية صندوق مرن؟"
}
]
},
@@ -43,7 +43,7 @@
{
"type": "property_value",
"value": { "property": "gap", "expected": "1rem" },
"message": "اضبط <kbd>gap: 1rem</kbd>"
"message": "ما الخاصية التي تُنشئ تباعداً بين عناصر flex بدون استخدام الهوامش؟"
}
]
},
@@ -64,7 +64,7 @@
{
"type": "property_value",
"value": { "property": "justify-content", "expected": "space-between" },
"message": "اضبط <kbd>justify-content: space-between</kbd>"
"message": "ما قيمة <kbd>justify-content</kbd> التي تدفع العنصر الأول والأخير إلى الحواف المتقابلة؟"
}
]
},
@@ -85,7 +85,7 @@
{
"type": "property_value",
"value": { "property": "align-items", "expected": "center" },
"message": "اضبط <kbd>align-items: center</kbd>"
"message": "ما الخاصية التي تُحاذي عناصر flex على طول المحور المتقاطع؟"
}
]
},
@@ -106,7 +106,7 @@
{
"type": "property_value",
"value": { "property": "flex-wrap", "expected": "wrap" },
"message": "اضبط <kbd>flex-wrap: wrap</kbd>"
"message": "ما الخاصية التي تسمح لعناصر flex بالتدفق إلى أسطر متعددة؟"
}
]
},
@@ -127,7 +127,7 @@
{
"type": "property_value",
"value": { "property": "flex", "expected": "1" },
"message": "اضبط <kbd>flex: 1</kbd>"
"message": "ما الخاصية التي تجعل عنصر flex ينمو لملء المساحة المتبقية؟"
}
]
}