init: initialize project - 2 games

This commit is contained in:
Ahmad EL Masri 2025-06-05 06:32:33 +02:00
commit 4740d0003b
Signed by: ahmad
GPG key ID: 592CDF2A42C69D74
7 changed files with 1784 additions and 0 deletions

215
find-and-write/index.html Normal file
View file

@ -0,0 +1,215 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Classroom Word Search Game</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.5/babel.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect } = React;
function WordSearchGame() {
const wordLists = {
animals: ['elephant', 'giraffe', 'penguin', 'dolphin', 'kangaroo', 'octopus', 'butterfly', 'zebra'],
colors: ['purple', 'orange', 'yellow', 'green', 'blue', 'red', 'brown', 'pink'],
food: ['pizza', 'banana', 'cookie', 'apple', 'sandwich', 'pasta', 'carrot', 'burger'],
school: ['pencil', 'eraser', 'notebook', 'teacher', 'student', 'library', 'classroom', 'homework'],
// Arabic categories for beginners
arabicAnimals: ['فيل', 'أسد', 'قطة', 'كلب', 'زرافة', 'فأر', 'سمكة', 'طائر'],
arabicColors: ['أحمر', 'أزرق', 'أخضر', 'أصفر', 'أسود', 'أبيض', 'بني', 'برتقالي'],
arabicNumbers: ['واحد', 'اثنان', 'ثلاثة', 'أربعة', 'خمسة', 'ستة', 'سبعة', 'ثمانية'],
arabicGreetings: ['مرحبا', 'صباح الخير', 'مساء الخير', 'شكرا', 'عفوا', 'مع السلامة', 'كيف حالك', 'أنا بخير']
};
const [category, setCategory] = useState('animals');
const [isArabic, setIsArabic] = useState(false);
const [displayedWords, setDisplayedWords] = useState([]);
const [timer, setTimer] = useState(300);
const randomPosition = () => ({
left: `${Math.random() * 70 + 15}%`,
top: `${Math.random() * 50 + 20}%`, // Reduced vertical range to avoid bottom section
transform: `rotate(${Math.random() * 360}deg)`
});
useEffect(() => {
// When language is toggled, update to appropriate category
if (isArabic && !category.startsWith('arabic')) {
setCategory('arabicAnimals');
} else if (!isArabic && category.startsWith('arabic')) {
setCategory('animals');
}
}, [isArabic]);
useEffect(() => {
const words = wordLists[category].map((word, index) => ({
id: index,
text: word,
...randomPosition()
}));
setDisplayedWords(words);
}, [category]);
useEffect(() => {
const interval = setInterval(() => {
setTimer((prev) => (prev > 0 ? prev - 1 : 0));
}, 1000);
return () => clearInterval(interval);
}, []);
// Reset timer when language changes
useEffect(() => {
setTimer(300);
}, [isArabic]);
const changeCategory = () => {
// Filter categories based on language selection
const categories = Object.keys(wordLists).filter(cat =>
isArabic ? cat.startsWith('arabic') : !cat.startsWith('arabic')
);
const currentIndex = categories.indexOf(category);
const nextIndex = (currentIndex + 1) % categories.length;
setCategory(categories[nextIndex]);
setTimer(300);
};
const toggleLanguage = () => {
setIsArabic(!isArabic);
// Set to first category of the selected language
const categories = Object.keys(wordLists).filter(cat =>
!isArabic ? cat.startsWith('arabic') : !cat.startsWith('arabic')
);
setCategory(categories[0]);
setTimer(300);
};
// Format category name for display
const formatCategoryName = (cat) => {
if (cat.startsWith('arabic')) {
// Convert arabicAnimals to "Arabic Animals"
return cat.replace('arabic', 'Arabic ').replace(/([A-Z])/g, ' $1').trim();
}
return cat;
};
return (
<div className="relative w-full h-screen bg-gray-100 overflow-hidden">
<div className="absolute top-0 left-0 right-0 p-4 bg-white shadow-md flex justify-between items-center">
<div className="flex items-center gap-2">
<span className="text-2xl">📚</span>
<span className="text-2xl font-bold">Find and Write: {formatCategoryName(category)}</span>
</div>
<div className="flex items-center gap-4">
<button
onClick={toggleLanguage}
className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600"
>
{isArabic ? "Switch to English" : "Switch to Arabic"}
</button>
<button
onClick={changeCategory}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Change Category
</button>
<div className="text-xl">
Words to find: {wordLists[category].length}
</div>
<div className="text-xl">
Time: {Math.floor(timer / 60)}:{(timer % 60).toString().padStart(2, '0')}
</div>
</div>
</div>
<div className="absolute top-20 left-4 right-4 bg-yellow-100 p-4 rounded-lg shadow">
<p className="text-lg">
🤫 Silently find and write down as many {formatCategoryName(category)} as you can!
Look carefully - words might be rotated!
{isArabic && (
<span className="block mt-2 text-gray-700">
<strong>Beginner tip:</strong> Try to find and memorize these Arabic words. Check the help section at the bottom for learning tips!
</span>
)}
</p>
</div>
<div className="mt-32 relative w-full h-full">
{displayedWords.map((word) => (
<div
key={word.id}
className={`absolute font-bold select-none ${isArabic ? 'text-3xl' : 'text-4xl'} text-gray-700`}
style={{
left: word.left,
top: word.top,
transform: word.transform,
direction: isArabic ? 'rtl' : 'ltr',
fontFamily: isArabic ? "'Arial', 'Tahoma', sans-serif" : 'inherit'
}}
>
{word.text}
</div>
))}
</div>
{isArabic && (
<div className="fixed bottom-0 left-0 right-0 bg-blue-100 p-2 shadow" style={{ maxHeight: '25vh', overflowY: 'auto' }}>
<button
className="absolute top-1 right-2 bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center text-xs"
onClick={() => document.querySelector('.help-section').classList.toggle('hidden')}
>
×
</button>
<h3 className="text-lg font-bold text-center">Arabic Learning Guide</h3>
<div className="help-section grid grid-cols-1 md:grid-cols-4 gap-2 text-sm mt-1">
<div>
<strong>Animals (الحيوانات):</strong>
<ul className="list-disc pl-5">
<li>فيل - elephant</li>
<li>أسد - lion</li>
<li>قطة - cat</li>
<li>كلب - dog</li>
</ul>
</div>
<div>
<strong>Colors (الألوان):</strong>
<ul className="list-disc pl-5">
<li>أحمر - red</li>
<li>أزرق - blue</li>
<li>أخضر - green</li>
<li>أصفر - yellow</li>
</ul>
</div>
<div>
<strong>Numbers (الأرقام):</strong>
<ul className="list-disc pl-5">
<li>واحد - one</li>
<li>اثنان - two</li>
<li>ثلاثة - three</li>
<li>أربعة - four</li>
</ul>
</div>
<div>
<strong>Greetings (التحيات):</strong>
<ul className="list-disc pl-5">
<li>مرحبا - hello</li>
<li>شكرا - thank you</li>
<li>مع السلامة - goodbye</li>
<li>كيف حالك - how are you</li>
</ul>
</div>
</div>
</div>
)}
</div>
);
}
ReactDOM.render(<WordSearchGame />, document.getElementById('root'));
</script>
</body>
</html>