diff --git a/messages/ar.json b/messages/ar.json index b0752fa8..8a316410 100644 --- a/messages/ar.json +++ b/messages/ar.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "فكر خطوة بخطوة", "problem": "المشكلة:", "withoutMagic": "بدون الكلمات السحرية:", "addMagicWords": "أضف الكلمات السحرية!", "magicWordsActive": "تمت إضافة الكلمات السحرية!", "nextStep": "اكشف الخطوة التالية", "withMagic": "مع التفكير خطوة بخطوة:", "retry": "حاول مرة أخرى" }, "promptLab": { "title": "مختبر الأوامر", "progress": "التحسينات", "yourPrompt": "أمرك:", "aiSays": "رد الذكاء الاصطناعي:", "addDetails": "أضف تحسينات:", "success": "أمرك الآن محدد جداً!", "retry": "ابدأ من جديد" }, "wordPredictor": { "title": "كيف يفكر الذكاء الاصطناعي", "instruction": "الذكاء الاصطناعي يخمن الكلمة التالية الأكثر احتمالاً. هل يمكنك التفكير مثله؟", "aiThinks": "الذكاء الاصطناعي يقرأ:", "thinkingDefault": "همم، أي كلمة ستكون منطقية هنا؟", "check": "تحقق من تخميني!", "correct": "أنت تفكر مثل الذكاء الاصطناعي!", "tryAgain": "ليس تماماً! الذكاء الاصطناعي يختار الكلمة الأكثر احتمالاً.", "retry": "حاول مرة أخرى" }, - "settings": { "title": "الإعدادات", "language": "اللغة", "progress": "تقدمك", "stars": "النجوم", "completed": "المكتمل", "resetTitle": "إعادة تعيين التقدم", "resetButton": "إعادة تعيين كل التقدم", "resetWarning": "سيحذف هذا كل نجومك وتقدمك. هل أنت متأكد؟", "resetConfirm": "نعم، أعد تعيين كل شيء", "resetComplete": "تم إعادة التعيين! جارٍ إعادة التحميل...", "cancel": "إلغاء" } + "settings": { "title": "الإعدادات", "music": "الموسيقى", "language": "اللغة", "progress": "تقدمك", "stars": "النجوم", "completed": "المكتمل", "resetTitle": "إعادة تعيين التقدم", "resetButton": "إعادة تعيين كل التقدم", "resetWarning": "سيحذف هذا كل نجومك وتقدمك. هل أنت متأكد؟", "resetConfirm": "نعم، أعد تعيين كل شيء", "resetComplete": "تم إعادة التعيين! جارٍ إعادة التحميل...", "cancel": "إلغاء" } } } diff --git a/messages/az.json b/messages/az.json index 97afd6c9..aded4f14 100644 --- a/messages/az.json +++ b/messages/az.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "Addım-addım Düşün", "problem": "Problem:", "withoutMagic": "Sehrli sözlər olmadan:", "addMagicWords": "Sehrli Sözləri Əlavə Et!", "magicWordsActive": "Sehrli sözlər əlavə edildi!", "nextStep": "Növbəti Addımı Göstər", "withMagic": "Addım-addım düşünmə ilə:", "retry": "Yenidən cəhd et" }, "promptLab": { "title": "Prompt Laboratoriyası", "progress": "Təkmilləşdirmələr", "yourPrompt": "Sənin Promptun:", "aiSays": "AI Cavabı:", "addDetails": "Təkmilləşdirmə əlavə et:", "success": "Promptun indi çox spesifikdir!", "retry": "Yenidən başla" }, "wordPredictor": { "title": "AI Necə Düşünür", "instruction": "AI ən çox ehtimal olunan növbəti sözü təxmin edir. AI kimi düşünə bilərsən?", "aiThinks": "AI oxuyur:", "thinkingDefault": "Hmm, burada hansı söz ən məntiqli olardı?", "check": "Cavabımı yoxla!", "correct": "AI kimi düşünürsən!", "tryAgain": "Tam deyil! AI ən çox ehtimal olunan sözü seçir.", "retry": "Yenidən cəhd et" }, - "settings": { "title": "Parametrlər", "language": "Dil", "progress": "Tərəqqin", "stars": "Ulduzlar", "completed": "Tamamlandı", "resetTitle": "Tərəqqini Sıfırla", "resetButton": "Hamısını Sıfırla", "resetWarning": "Bu bütün ulduzları və tərəqqini siləcək. Əminsən?", "resetConfirm": "Bəli, Hamısını Sıfırla", "resetComplete": "Tərəqqi sıfırlandı! Yenidən yüklənir...", "cancel": "Ləğv et" } + "settings": { "title": "Tənzimləmələr", "music": "Musiqi", "language": "Dil", "progress": "Tərəqqin", "stars": "Ulduzlar", "completed": "Tamamlandı", "resetTitle": "Tərəqqini Sıfırla", "resetButton": "Hamısını Sıfırla", "resetWarning": "Bu bütün ulduzları və tərəqqini siləcək. Əminsən?", "resetConfirm": "Bəli, Hamısını Sıfırla", "resetComplete": "Tərəqqi sıfırlandı! Yenidən yüklənir...", "cancel": "Ləğv et" } } } diff --git a/messages/de.json b/messages/de.json index d4e79c62..4b36b143 100644 --- a/messages/de.json +++ b/messages/de.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "Schritt für Schritt denken", "problem": "Das Problem:", "withoutMagic": "Ohne Zauberwörter:", "addMagicWords": "Füge Zauberwörter hinzu!", "magicWordsActive": "Zauberwörter hinzugefügt!", "nextStep": "Nächsten Schritt zeigen", "withMagic": "Mit Schritt-für-Schritt-Denken:", "retry": "Nochmal versuchen" }, "promptLab": { "title": "Prompt-Labor", "progress": "Verbesserungen", "yourPrompt": "Dein Prompt:", "aiSays": "KI-Antwort:", "addDetails": "Verbesserungen hinzufügen:", "success": "Dein Prompt ist jetzt super spezifisch!", "retry": "Von vorn" }, "wordPredictor": { "title": "Wie KI denkt", "instruction": "KI errät das wahrscheinlichste nächste Wort. Kannst du wie KI denken?", "aiThinks": "KI liest:", "thinkingDefault": "Hmm, welches Wort würde hier Sinn machen?", "check": "Meine Antwort prüfen!", "correct": "Du denkst wie KI!", "tryAgain": "Nicht ganz! KI wählt das wahrscheinlichste Wort.", "retry": "Nochmal versuchen" }, - "settings": { "title": "Einstellungen", "language": "Sprache", "progress": "Dein Fortschritt", "stars": "Sterne", "completed": "Abgeschlossen", "resetTitle": "Fortschritt zurücksetzen", "resetButton": "Alles zurücksetzen", "resetWarning": "Dies löscht alle Sterne und Fortschritt. Bist du sicher?", "resetConfirm": "Ja, alles zurücksetzen", "resetComplete": "Fortschritt zurückgesetzt! Wird neu geladen...", "cancel": "Abbrechen" } + "settings": { "title": "Einstellungen", "music": "Musik", "language": "Sprache", "progress": "Dein Fortschritt", "stars": "Sterne", "completed": "Abgeschlossen", "resetTitle": "Fortschritt zurücksetzen", "resetButton": "Alles zurücksetzen", "resetWarning": "Dies löscht alle Sterne und Fortschritt. Bist du sicher?", "resetConfirm": "Ja, alles zurücksetzen", "resetComplete": "Fortschritt zurückgesetzt! Wird neu geladen...", "cancel": "Abbrechen" } } } diff --git a/messages/el.json b/messages/el.json index 2b73a4e9..9eaba0ad 100644 --- a/messages/el.json +++ b/messages/el.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "Σκέψου Βήμα-Βήμα", "problem": "Το Πρόβλημα:", "withoutMagic": "Χωρίς μαγικές λέξεις:", "addMagicWords": "Πρόσθεσε Μαγικές Λέξεις!", "magicWordsActive": "Μαγικές λέξεις προστέθηκαν!", "nextStep": "Αποκάλυψη Επόμενου Βήματος", "withMagic": "Με σκέψη βήμα-βήμα:", "retry": "Προσπάθησε ξανά" }, "promptLab": { "title": "Εργαστήριο Prompts", "progress": "Βελτιώσεις", "yourPrompt": "Το Prompt σου:", "aiSays": "Απάντηση AI:", "addDetails": "Πρόσθεσε βελτιώσεις:", "success": "Το prompt σου είναι τώρα πολύ συγκεκριμένο!", "retry": "Από την αρχή" }, "wordPredictor": { "title": "Πώς Σκέφτεται η AI", "instruction": "Η AI μαντεύει την πιο πιθανή επόμενη λέξη. Μπορείς να σκεφτείς σαν AI;", "aiThinks": "Η AI διαβάζει:", "thinkingDefault": "Χμμ, ποια λέξη θα είχε νόημα εδώ;", "check": "Έλεγξε την απάντησή μου!", "correct": "Σκέφτεσαι σαν AI!", "tryAgain": "Όχι ακριβώς! Η AI διαλέγει την πιο πιθανή λέξη.", "retry": "Προσπάθησε ξανά" }, - "settings": { "title": "Ρυθμίσεις", "language": "Γλώσσα", "progress": "Η Πρόοδός σου", "stars": "Αστέρια", "completed": "Ολοκληρώθηκε", "resetTitle": "Επαναφορά Προόδου", "resetButton": "Επαναφορά Όλων", "resetWarning": "Αυτό θα διαγράψει όλα τα αστέρια και την πρόοδο. Είσαι σίγουρος;", "resetConfirm": "Ναι, Επαναφορά Όλων", "resetComplete": "Η πρόοδος επαναφέρθηκε! Επαναφόρτωση...", "cancel": "Ακύρωση" } + "settings": { "title": "Ρυθμίσεις", "music": "Μουσική", "language": "Γλώσσα", "progress": "Η Πρόοδός σου", "stars": "Αστέρια", "completed": "Ολοκληρώθηκε", "resetTitle": "Επαναφορά Προόδου", "resetButton": "Επαναφορά Όλων", "resetWarning": "Αυτό θα διαγράψει όλα τα αστέρια και την πρόοδο. Είσαι σίγουρος;", "resetConfirm": "Ναι, Επαναφορά Όλων", "resetComplete": "Η πρόοδος επαναφέρθηκε! Επαναφόρτωση...", "cancel": "Ακύρωση" } } } diff --git a/messages/en.json b/messages/en.json index 74ace7ad..af3f141a 100644 --- a/messages/en.json +++ b/messages/en.json @@ -1633,6 +1633,7 @@ }, "settings": { "title": "Settings", + "music": "Music", "language": "Language", "progress": "Your Progress", "stars": "Stars", diff --git a/messages/es.json b/messages/es.json index 23ebeccc..d13b951b 100644 --- a/messages/es.json +++ b/messages/es.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "Piensa Paso a Paso", "problem": "El Problema:", "withoutMagic": "Sin palabras mágicas:", "addMagicWords": "¡Añade las Palabras Mágicas!", "magicWordsActive": "¡Palabras mágicas añadidas!", "nextStep": "Revelar Siguiente Paso", "withMagic": "Con pensamiento paso a paso:", "retry": "Intentar de nuevo" }, "promptLab": { "title": "Laboratorio de Prompts", "progress": "Mejoras", "yourPrompt": "Tu Prompt:", "aiSays": "Respuesta de IA:", "addDetails": "Añadir mejoras:", "success": "¡Tu prompt ahora es súper específico!", "retry": "Empezar de nuevo" }, "wordPredictor": { "title": "Cómo Piensa la IA", "instruction": "La IA adivina la palabra más probable. ¿Puedes pensar como IA?", "aiThinks": "La IA está leyendo:", "thinkingDefault": "Hmm, ¿qué palabra tendría más sentido aquí?", "check": "¡Comprobar mi respuesta!", "correct": "¡Piensas como IA!", "tryAgain": "¡No del todo! La IA elige la palabra más probable.", "retry": "Intentar de nuevo" }, - "settings": { "title": "Configuración", "language": "Idioma", "progress": "Tu Progreso", "stars": "Estrellas", "completed": "Completados", "resetTitle": "Restablecer Progreso", "resetButton": "Restablecer Todo", "resetWarning": "Esto eliminará todas tus estrellas y progreso. ¿Estás seguro?", "resetConfirm": "Sí, Restablecer Todo", "resetComplete": "¡Progreso restablecido! Recargando...", "cancel": "Cancelar" } + "settings": { "title": "Configuración", "music": "Música", "language": "Idioma", "progress": "Tu Progreso", "stars": "Estrellas", "completed": "Completados", "resetTitle": "Restablecer Progreso", "resetButton": "Restablecer Todo", "resetWarning": "Esto eliminará todas tus estrellas y progreso. ¿Estás seguro?", "resetConfirm": "Sí, Restablecer Todo", "resetComplete": "¡Progreso restablecido! Recargando...", "cancel": "Cancelar" } } } diff --git a/messages/fa.json b/messages/fa.json index acd715c5..2bfb37b2 100644 --- a/messages/fa.json +++ b/messages/fa.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "قدم به قدم فکر کن", "problem": "مسئله:", "withoutMagic": "بدون کلمات جادویی:", "addMagicWords": "کلمات جادویی اضافه کن!", "magicWordsActive": "کلمات جادویی اضافه شد!", "nextStep": "قدم بعدی نشان بده", "withMagic": "با فکر قدم به قدم:", "retry": "دوباره تلاش کن" }, "promptLab": { "title": "آزمایشگاه پرامپت", "progress": "بهبودها", "yourPrompt": "پرامپت تو:", "aiSays": "پاسخ هوش مصنوعی:", "addDetails": "بهبود اضافه کن:", "success": "پرامپتت الان خیلی مشخصه!", "retry": "از اول" }, "wordPredictor": { "title": "هوش مصنوعی چطور فکر میکند", "instruction": "هوش مصنوعی محتملترین کلمه بعدی حدس میزند. میتونی مثل هوش مصنوعی فکر کنی?", "aiThinks": "هوش مصنوعی میخواند:", "thinkingDefault": "هوم، کدام کلمه اینجا منطقیتره؟", "check": "جوابم بررسی کن!", "correct": "مثل هوش مصنوعی فکر میکنی!", "tryAgain": "دقیقاً نه! هوش مصنوعی محتملترین کلمه انتخاب میکند.", "retry": "دوباره تلاش کن" }, - "settings": { "title": "تنظیمات", "language": "زبان", "progress": "پیشرفت تو", "stars": "ستارهها", "completed": "تکمیل شده", "resetTitle": "بازنشانی پیشرفت", "resetButton": "همه بازنشانی", "resetWarning": "این همه ستارهها و پیشرفت پاک میکند. مطمئنی؟", "resetConfirm": "بله، همه بازنشانی", "resetComplete": "پیشرفت بازنشانی شد! بارگذاری مجدد...", "cancel": "لغو" } + "settings": { "title": "تنظیمات", "music": "موسیقی", "language": "زبان", "progress": "پیشرفت تو", "stars": "ستارهها", "completed": "تکمیل شده", "resetTitle": "بازنشانی پیشرفت", "resetButton": "همه بازنشانی", "resetWarning": "این همه ستارهها و پیشرفت پاک میکند. مطمئنی؟", "resetConfirm": "بله، همه بازنشانی", "resetComplete": "پیشرفت بازنشانی شد! بارگذاری مجدد...", "cancel": "لغو" } } } diff --git a/messages/fr.json b/messages/fr.json index 75b37429..2e96dd7d 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "Penser Étape par Étape", "problem": "Le Problème :", "withoutMagic": "Sans mots magiques :", "addMagicWords": "Ajoute les Mots Magiques !", "magicWordsActive": "Mots magiques ajoutés !", "nextStep": "Révéler l'Étape Suivante", "withMagic": "Avec la pensée étape par étape :", "retry": "Réessayer" }, "promptLab": { "title": "Labo de Prompts", "progress": "Améliorations", "yourPrompt": "Ton Prompt :", "aiSays": "Réponse de l'IA :", "addDetails": "Ajouter des améliorations :", "success": "Ton prompt est maintenant super spécifique !", "retry": "Recommencer" }, "wordPredictor": { "title": "Comment l'IA Pense", "instruction": "L'IA devine le mot suivant le plus probable. Peux-tu penser comme l'IA ?", "aiThinks": "L'IA lit :", "thinkingDefault": "Hmm, quel mot aurait le plus de sens ici ?", "check": "Vérifier ma réponse !", "correct": "Tu penses comme l'IA !", "tryAgain": "Pas tout à fait ! L'IA choisit le mot le plus probable.", "retry": "Réessayer" }, - "settings": { "title": "Paramètres", "language": "Langue", "progress": "Ta Progression", "stars": "Étoiles", "completed": "Complétés", "resetTitle": "Réinitialiser la Progression", "resetButton": "Tout Réinitialiser", "resetWarning": "Cela supprimera toutes tes étoiles et ta progression. Es-tu sûr ?", "resetConfirm": "Oui, Tout Réinitialiser", "resetComplete": "Progression réinitialisée ! Rechargement...", "cancel": "Annuler" } + "settings": { "title": "Paramètres", "music": "Musique", "language": "Langue", "progress": "Ta Progression", "stars": "Étoiles", "completed": "Complétés", "resetTitle": "Réinitialiser la Progression", "resetButton": "Tout Réinitialiser", "resetWarning": "Cela supprimera toutes tes étoiles et ta progression. Es-tu sûr ?", "resetConfirm": "Oui, Tout Réinitialiser", "resetComplete": "Progression réinitialisée ! Rechargement...", "cancel": "Annuler" } } } diff --git a/messages/he.json b/messages/he.json index 77f02e95..166b0989 100644 --- a/messages/he.json +++ b/messages/he.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "חשוב צעד אחר צעד", "problem": "הבעיה:", "withoutMagic": "בלי מילות קסם:", "addMagicWords": "הוסף את מילות הקסם!", "magicWordsActive": "מילות הקסם נוספו!", "nextStep": "גלה את הצעד הבא", "withMagic": "עם חשיבה צעד אחר צעד:", "retry": "נסה שוב" }, "promptLab": { "title": "מעבדת פרומפטים", "progress": "שיפורים", "yourPrompt": "הפרומפט שלך:", "aiSays": "תשובת AI:", "addDetails": "הוסף שיפורים:", "success": "הפרומפט שלך עכשיו ספציפי מאוד!", "retry": "התחל מחדש" }, "wordPredictor": { "title": "איך AI חושב", "instruction": "AI מנחש את המילה הסבירה ביותר. אתה יכול לחשוב כמו AI?", "aiThinks": "AI קורא:", "thinkingDefault": "הממ, איזו מילה תהיה הגיונית כאן?", "check": "בדוק את התשובה שלי!", "correct": "אתה חושב כמו AI!", "tryAgain": "לא בדיוק! AI בוחר את המילה הסבירה ביותר.", "retry": "נסה שוב" }, - "settings": { "title": "הגדרות", "language": "שפה", "progress": "ההתקדמות שלך", "stars": "כוכבים", "completed": "הושלם", "resetTitle": "אפס התקדמות", "resetButton": "אפס הכל", "resetWarning": "זה ימחק את כל הכוכבים וההתקדמות. בטוח?", "resetConfirm": "כן, אפס הכל", "resetComplete": "התקדמות אופסה! טוען מחדש...", "cancel": "ביטול" } + "settings": { "title": "הגדרות", "music": "מוזיקה", "language": "שפה", "progress": "ההתקדמות שלך", "stars": "כוכבים", "completed": "הושלם", "resetTitle": "אפס התקדמות", "resetButton": "אפס הכל", "resetWarning": "זה ימחק את כל הכוכבים וההתקדמות. בטוח?", "resetConfirm": "כן, אפס הכל", "resetComplete": "התקדמות אופסה! טוען מחדש...", "cancel": "ביטול" } } } diff --git a/messages/it.json b/messages/it.json index b10bc2c7..2c332039 100644 --- a/messages/it.json +++ b/messages/it.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "Pensa Passo dopo Passo", "problem": "Il Problema:", "withoutMagic": "Senza parole magiche:", "addMagicWords": "Aggiungi le Parole Magiche!", "magicWordsActive": "Parole magiche aggiunte!", "nextStep": "Rivela Passo Successivo", "withMagic": "Con il pensiero passo dopo passo:", "retry": "Riprova" }, "promptLab": { "title": "Laboratorio Prompt", "progress": "Miglioramenti", "yourPrompt": "Il Tuo Prompt:", "aiSays": "Risposta IA:", "addDetails": "Aggiungi miglioramenti:", "success": "Il tuo prompt ora è super specifico!", "retry": "Ricomincia" }, "wordPredictor": { "title": "Come Pensa l'IA", "instruction": "L'IA indovina la parola più probabile. Puoi pensare come l'IA?", "aiThinks": "L'IA sta leggendo:", "thinkingDefault": "Hmm, quale parola avrebbe più senso qui?", "check": "Verifica la mia risposta!", "correct": "Pensi come l'IA!", "tryAgain": "Non proprio! L'IA sceglie la parola più probabile.", "retry": "Riprova" }, - "settings": { "title": "Impostazioni", "language": "Lingua", "progress": "I Tuoi Progressi", "stars": "Stelle", "completed": "Completati", "resetTitle": "Reimposta Progressi", "resetButton": "Reimposta Tutto", "resetWarning": "Questo cancellerà tutte le stelle e i progressi. Sei sicuro?", "resetConfirm": "Sì, Reimposta Tutto", "resetComplete": "Progressi reimpostati! Ricaricamento...", "cancel": "Annulla" } + "settings": { "title": "Impostazioni", "music": "Musica", "language": "Lingua", "progress": "I Tuoi Progressi", "stars": "Stelle", "completed": "Completati", "resetTitle": "Reimposta Progressi", "resetButton": "Reimposta Tutto", "resetWarning": "Questo cancellerà tutte le stelle e i progressi. Sei sicuro?", "resetConfirm": "Sì, Reimposta Tutto", "resetComplete": "Progressi reimpostati! Ricaricamento...", "cancel": "Annulla" } } } diff --git a/messages/ja.json b/messages/ja.json index 23937e68..8d1f41c6 100644 --- a/messages/ja.json +++ b/messages/ja.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "ステップバイステップで考えよう", "problem": "問題:", "withoutMagic": "魔法の言葉なし:", "addMagicWords": "魔法の言葉を追加!", "magicWordsActive": "魔法の言葉を追加した!", "nextStep": "次のステップを見る", "withMagic": "ステップバイステップ思考で:", "retry": "もう一度" }, "promptLab": { "title": "プロンプトラボ", "progress": "改善", "yourPrompt": "あなたのプロンプト:", "aiSays": "AIの応答:", "addDetails": "改善を追加:", "success": "プロンプトがとても具体的になった!", "retry": "最初から" }, "wordPredictor": { "title": "AIの考え方", "instruction": "AIは最も可能性の高い次の単語を推測する。AIのように考えられる?", "aiThinks": "AIが読んでいる:", "thinkingDefault": "うーん、ここでどの単語が一番意味がある?", "check": "答えをチェック!", "correct": "AIのように考えてる!", "tryAgain": "違う!AIは最も可能性の高い単語を選ぶ。", "retry": "もう一度" }, - "settings": { "title": "設定", "language": "言語", "progress": "あなたの進捗", "stars": "スター", "completed": "完了", "resetTitle": "進捗をリセット", "resetButton": "すべてリセット", "resetWarning": "すべてのスターと進捗が削除されます。よろしいですか?", "resetConfirm": "はい、すべてリセット", "resetComplete": "進捗をリセットしました!再読み込み中...", "cancel": "キャンセル" } + "settings": { "title": "設定", "music": "音楽", "language": "言語", "progress": "あなたの進捗", "stars": "スター", "completed": "完了", "resetTitle": "進捗をリセット", "resetButton": "すべてリセット", "resetWarning": "すべてのスターと進捗が削除されます。よろしいですか?", "resetConfirm": "はい、すべてリセット", "resetComplete": "進捗をリセットしました!再読み込み中...", "cancel": "キャンセル" } } } diff --git a/messages/ko.json b/messages/ko.json index 0bfd5241..05e1062b 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "단계별로 생각하기", "problem": "문제:", "withoutMagic": "마법의 단어 없이:", "addMagicWords": "마법의 단어를 추가하세요!", "magicWordsActive": "마법의 단어가 추가됐어요!", "nextStep": "다음 단계 보기", "withMagic": "단계별 사고로:", "retry": "다시 시도" }, "promptLab": { "title": "프롬프트 연구소", "progress": "개선", "yourPrompt": "당신의 프롬프트:", "aiSays": "AI 응답:", "addDetails": "개선 추가:", "success": "프롬프트가 아주 구체적이 됐어요!", "retry": "처음부터" }, "wordPredictor": { "title": "AI가 생각하는 방법", "instruction": "AI는 가장 가능성 높은 다음 단어를 추측해요. AI처럼 생각할 수 있나요?", "aiThinks": "AI가 읽고 있어요:", "thinkingDefault": "음, 어떤 단어가 여기에 가장 맞을까?", "check": "내 답 확인!", "correct": "AI처럼 생각하고 있어요!", "tryAgain": "아니에요! AI는 가장 가능성 높은 단어를 선택해요.", "retry": "다시 시도" }, - "settings": { "title": "설정", "language": "언어", "progress": "진행 상황", "stars": "별", "completed": "완료", "resetTitle": "진행 상황 초기화", "resetButton": "모두 초기화", "resetWarning": "모든 별과 진행 상황이 삭제됩니다. 확실한가요?", "resetConfirm": "네, 모두 초기화", "resetComplete": "진행 상황 초기화됨! 새로고침 중...", "cancel": "취소" } + "settings": { "title": "설정", "music": "음악", "language": "언어", "progress": "진행 상황", "stars": "별", "completed": "완료", "resetTitle": "진행 상황 초기화", "resetButton": "모두 초기화", "resetWarning": "모든 별과 진행 상황이 삭제됩니다. 확실한가요?", "resetConfirm": "네, 모두 초기화", "resetComplete": "진행 상황 초기화됨! 새로고침 중...", "cancel": "취소" } } } diff --git a/messages/nl.json b/messages/nl.json index 8954e4ed..9eaf727d 100644 --- a/messages/nl.json +++ b/messages/nl.json @@ -1633,6 +1633,7 @@ }, "settings": { "title": "Instellingen", + "music": "Muziek", "language": "Taal", "progress": "Jouw voortgang", "stars": "Sterren", diff --git a/messages/pt.json b/messages/pt.json index 4f7137b0..de3314ca 100644 --- a/messages/pt.json +++ b/messages/pt.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "Pense Passo a Passo", "problem": "O Problema:", "withoutMagic": "Sem palavras mágicas:", "addMagicWords": "Adicione as Palavras Mágicas!", "magicWordsActive": "Palavras mágicas adicionadas!", "nextStep": "Revelar Próximo Passo", "withMagic": "Com pensamento passo a passo:", "retry": "Tentar de novo" }, "promptLab": { "title": "Laboratório de Prompts", "progress": "Melhorias", "yourPrompt": "Seu Prompt:", "aiSays": "Resposta da IA:", "addDetails": "Adicionar melhorias:", "success": "Seu prompt agora é super específico!", "retry": "Recomeçar" }, "wordPredictor": { "title": "Como a IA Pensa", "instruction": "A IA adivinha a palavra mais provável. Você consegue pensar como IA?", "aiThinks": "A IA está lendo:", "thinkingDefault": "Hmm, qual palavra faria mais sentido aqui?", "check": "Verificar minha resposta!", "correct": "Você pensa como IA!", "tryAgain": "Não exatamente! A IA escolhe a palavra mais provável.", "retry": "Tentar de novo" }, - "settings": { "title": "Configurações", "language": "Idioma", "progress": "Seu Progresso", "stars": "Estrelas", "completed": "Completados", "resetTitle": "Redefinir Progresso", "resetButton": "Redefinir Tudo", "resetWarning": "Isso apagará todas as estrelas e progresso. Tem certeza?", "resetConfirm": "Sim, Redefinir Tudo", "resetComplete": "Progresso redefinido! Recarregando...", "cancel": "Cancelar" } + "settings": { "title": "Configurações", "music": "Música", "language": "Idioma", "progress": "Seu Progresso", "stars": "Estrelas", "completed": "Completados", "resetTitle": "Redefinir Progresso", "resetButton": "Redefinir Tudo", "resetWarning": "Isso apagará todas as estrelas e progresso. Tem certeza?", "resetConfirm": "Sim, Redefinir Tudo", "resetComplete": "Progresso redefinido! Recarregando...", "cancel": "Cancelar" } } } diff --git a/messages/ru.json b/messages/ru.json index 279bff31..d64990da 100644 --- a/messages/ru.json +++ b/messages/ru.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "Думай пошагово", "problem": "Проблема:", "withoutMagic": "Без волшебных слов:", "addMagicWords": "Добавь волшебные слова!", "magicWordsActive": "Волшебные слова добавлены!", "nextStep": "Показать следующий шаг", "withMagic": "С пошаговым мышлением:", "retry": "Попробуй снова" }, "promptLab": { "title": "Лаборатория промптов", "progress": "Улучшения", "yourPrompt": "Твой промпт:", "aiSays": "Ответ ИИ:", "addDetails": "Добавь улучшения:", "success": "Твой промпт теперь очень конкретный!", "retry": "Сначала" }, "wordPredictor": { "title": "Как думает ИИ", "instruction": "ИИ угадывает наиболее вероятное следующее слово. Можешь думать как ИИ?", "aiThinks": "ИИ читает:", "thinkingDefault": "Хмм, какое слово имело бы смысл здесь?", "check": "Проверь мой ответ!", "correct": "Ты думаешь как ИИ!", "tryAgain": "Не совсем! ИИ выбирает наиболее вероятное слово.", "retry": "Попробуй снова" }, - "settings": { "title": "Настройки", "language": "Язык", "progress": "Твой прогресс", "stars": "Звёзды", "completed": "Завершено", "resetTitle": "Сбросить прогресс", "resetButton": "Сбросить всё", "resetWarning": "Это удалит все звёзды и прогресс. Уверен?", "resetConfirm": "Да, сбросить всё", "resetComplete": "Прогресс сброшен! Перезагрузка...", "cancel": "Отмена" } + "settings": { "title": "Настройки", "music": "Музыка", "language": "Язык", "progress": "Твой прогресс", "stars": "Звёзды", "completed": "Завершено", "resetTitle": "Сбросить прогресс", "resetButton": "Сбросить всё", "resetWarning": "Это удалит все звёзды и прогресс. Уверен?", "resetConfirm": "Да, сбросить всё", "resetComplete": "Прогресс сброшен! Перезагрузка...", "cancel": "Отмена" } } } diff --git a/messages/tr.json b/messages/tr.json index 9dd9dbfe..a0c2ca25 100644 --- a/messages/tr.json +++ b/messages/tr.json @@ -1566,6 +1566,7 @@ }, "settings": { "title": "Ayarlar", + "music": "Müzik", "language": "Dil", "progress": "İlerlemeniz", "stars": "Yıldız", diff --git a/messages/zh.json b/messages/zh.json index 2618e838..b189d2da 100644 --- a/messages/zh.json +++ b/messages/zh.json @@ -1445,6 +1445,6 @@ "stepByStep": { "title": "逐步思考", "problem": "问题:", "withoutMagic": "没有魔法词语:", "addMagicWords": "添加魔法词语!", "magicWordsActive": "魔法词语已添加!", "nextStep": "显示下一步", "withMagic": "逐步思考:", "retry": "再试一次" }, "promptLab": { "title": "提示词实验室", "progress": "改进", "yourPrompt": "你的提示词:", "aiSays": "AI回应:", "addDetails": "添加改进:", "success": "你的提示词现在非常具体!", "retry": "重新开始" }, "wordPredictor": { "title": "AI如何思考", "instruction": "AI猜测最可能的下一个词。你能像AI一样思考吗?", "aiThinks": "AI正在阅读:", "thinkingDefault": "嗯,哪个词在这里最有意义?", "check": "检查我的答案!", "correct": "你像AI一样思考!", "tryAgain": "不太对!AI选择最可能的词。", "retry": "再试一次" }, - "settings": { "title": "设置", "language": "语言", "progress": "你的进度", "stars": "星星", "completed": "已完成", "resetTitle": "重置进度", "resetButton": "重置全部", "resetWarning": "这将删除所有星星和进度。确定吗?", "resetConfirm": "是的,重置全部", "resetComplete": "进度已重置!正在重新加载...", "cancel": "取消" } + "settings": { "title": "设置", "music": "音乐", "language": "语言", "progress": "你的进度", "stars": "星星", "completed": "已完成", "resetTitle": "重置进度", "resetButton": "重置全部", "resetWarning": "这将删除所有星星和进度。确定吗?", "resetConfirm": "是的,重置全部", "resetComplete": "进度已重置!正在重新加载...", "cancel": "取消" } } } diff --git a/public/kids-music.mp3 b/public/kids-music.mp3 new file mode 100644 index 00000000..68161d77 Binary files /dev/null and b/public/kids-music.mp3 differ diff --git a/src/app/kids/layout.tsx b/src/app/kids/layout.tsx index 4ca1a34b..5cf75020 100644 --- a/src/app/kids/layout.tsx +++ b/src/app/kids/layout.tsx @@ -1,7 +1,7 @@ import { Schoolbell } from "next/font/google"; import { getLocale } from "next-intl/server"; import { KidsHeader } from "@/components/kids/layout/kids-header"; -import { BackgroundMusic } from "@/components/kids/layout/background-music"; +import { MusicProvider } from "@/components/kids/layout/background-music"; import { LevelProvider } from "@/components/kids/providers/level-context"; const RTL_LOCALES = ["ar", "he", "fa"]; @@ -40,6 +40,7 @@ export default async function KidsLayout({ return ( + {children} - + ); } diff --git a/src/components/kids/layout/background-music.tsx b/src/components/kids/layout/background-music.tsx index 04eaed14..36f80a7c 100644 --- a/src/components/kids/layout/background-music.tsx +++ b/src/components/kids/layout/background-music.tsx @@ -1,6 +1,24 @@ "use client"; -import { useState, useRef, useCallback } from "react"; +import { useState, useEffect, useRef, useCallback, createContext, useContext } from "react"; + +const MUSIC_ENABLED_KEY = "kids-music-enabled"; +const MUSIC_VOLUME_KEY = "kids-music-volume"; + +// Shared audio instance and context for cross-component communication +interface MusicContextType { + isPlaying: boolean; + volume: number; + setIsPlaying: (playing: boolean) => void; + setVolume: (volume: number) => void; + audioRef: React.RefObject; +} + +const MusicContext = createContext(null); + +export function useMusicContext() { + return useContext(MusicContext); +} // Pixel art speaker icons function PixelSpeakerOn() { @@ -30,304 +48,125 @@ function PixelSpeakerOff() { ); } -// 8-bit chiptune music generator using Web Audio API -class ChiptunePlayer { - private audioContext: AudioContext | null = null; - private masterGain: GainNode | null = null; - private isPlaying = false; - private intervalId: number | null = null; - private step = 0; +// Provider component that manages the audio element +export function MusicProvider({ children }: { children: React.ReactNode }) { + const audioRef = useRef(null); + const [isPlaying, setIsPlaying] = useState(false); + const [volume, setVolume] = useState(0.3); + const [hasInteracted, setHasInteracted] = useState(false); - // Fun bouncy 8-bit melody - playful and catchy! - private melody = [ - // Part 1: Bouncy intro - 523.25, 0, 659.25, 0, 783.99, 0, 659.25, 0, // C5 - E5 - G5 - E5 (bouncy) - 698.46, 0, 783.99, 0, 880.00, 783.99, 659.25, 0, // F5 - G5 - A5 G5 E5 (climb up!) - // Part 2: Silly descending - 783.99, 698.46, 659.25, 587.33, 523.25, 0, 392.00, 0, // G5 F5 E5 D5 C5 - G4 (slide down) - 440.00, 493.88, 523.25, 0, 659.25, 0, 523.25, 0, // A4 B4 C5 - E5 - C5 (pop back up) - // Part 3: Playful jumps - 392.00, 523.25, 392.00, 523.25, 659.25, 783.99, 659.25, 0, // G4 C5 G4 C5 E5 G5 E5 (jumping!) - 880.00, 0, 783.99, 0, 659.25, 523.25, 587.33, 659.25, // A5 - G5 - E5 C5 D5 E5 - // Part 4: Fun ending - 783.99, 0, 659.25, 0, 523.25, 587.33, 659.25, 783.99, // G5 - E5 - C5 D5 E5 G5 - 880.00, 783.99, 659.25, 523.25, 392.00, 0, 523.25, 0, // A5 G5 E5 C5 G4 - C5 (finish!) - ]; - - // Funky bass line - groovy! - private bass = [ - // Part 1 - 130.81, 0, 130.81, 164.81, 196.00, 0, 164.81, 0, // C3 - C3 E3 G3 - E3 - 174.61, 0, 196.00, 0, 220.00, 196.00, 164.81, 0, // F3 - G3 - A3 G3 E3 - // Part 2 - 196.00, 174.61, 164.81, 146.83, 130.81, 0, 98.00, 0, // G3 F3 E3 D3 C3 - G2 - 110.00, 123.47, 130.81, 0, 164.81, 0, 130.81, 0, // A2 B2 C3 - E3 - C3 - // Part 3 - 98.00, 130.81, 98.00, 130.81, 164.81, 196.00, 164.81, 0, // G2 C3 G2 C3 E3 G3 E3 - 220.00, 0, 196.00, 0, 164.81, 130.81, 146.83, 164.81, // A3 - G3 - E3 C3 D3 E3 - // Part 4 - 196.00, 0, 164.81, 0, 130.81, 146.83, 164.81, 196.00, // G3 - E3 - C3 D3 E3 G3 - 220.00, 196.00, 164.81, 130.81, 98.00, 0, 130.81, 0, // A3 G3 E3 C3 G2 - C3 - ]; - - async start() { - if (this.isPlaying) return; + // Load saved preferences + useEffect(() => { + const savedEnabled = localStorage.getItem(MUSIC_ENABLED_KEY); + const savedVolume = localStorage.getItem(MUSIC_VOLUME_KEY); - try { - this.audioContext = new (window.AudioContext || (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext)(); - - // Resume audio context if suspended (required by browsers) - if (this.audioContext.state === "suspended") { - await this.audioContext.resume(); + if (savedVolume) { + setVolume(parseFloat(savedVolume)); + } + + // Default to enabled if not set + if (savedEnabled === null || savedEnabled === "true") { + setIsPlaying(true); + } + }, []); + + // Create and manage audio element + useEffect(() => { + if (!audioRef.current) { + const audio = new Audio("/kids-music.mp3"); + audio.loop = true; + audio.volume = volume; + audioRef.current = audio; + } + + return () => { + if (audioRef.current) { + audioRef.current.pause(); + audioRef.current = null; } - - this.masterGain = this.audioContext.createGain(); - this.masterGain.gain.value = 0.2; - this.masterGain.connect(this.audioContext.destination); - this.isPlaying = true; - this.step = 0; + }; + }, []); - // Play notes at upbeat tempo - this.intervalId = window.setInterval(() => this.playStep(), 150); - } catch (error) { - console.error("Failed to start audio:", error); + // Update volume when it changes + useEffect(() => { + if (audioRef.current) { + audioRef.current.volume = volume; } - } + localStorage.setItem(MUSIC_VOLUME_KEY, volume.toString()); + }, [volume]); - private playStep() { - if (!this.audioContext || !this.masterGain) return; - - const now = this.audioContext.currentTime; - const noteIndex = this.step % this.melody.length; - - // Play melody (square wave for 8-bit sound) - skip if 0 (rest) - if (this.melody[noteIndex] > 0) { - this.playNote(this.melody[noteIndex], now, 0.12, "square", 0.12); - } + // Handle play/pause + useEffect(() => { + localStorage.setItem(MUSIC_ENABLED_KEY, isPlaying.toString()); - // Play bass (triangle wave) - louder and deeper, skip if 0 - if (this.bass[noteIndex] > 0) { - this.playNote(this.bass[noteIndex], now, 0.14, "triangle", 0.15); - // Add sub-bass for extra punch - this.playNote(this.bass[noteIndex] / 2, now, 0.14, "sine", 0.08); - } - - // Aggressive dubstep-style percussion - if (this.step % 8 === 0) { - this.playDrum(now, "kick"); - this.playDrum(now + 0.15, "kick"); // Double kick - } else if (this.step % 8 === 4) { - this.playDrum(now, "snare"); - } else if (this.step % 2 === 1) { - this.playDrum(now, "hihat"); - } + if (!audioRef.current) return; - // Wobble bass on every other beat for dubstep feel - if (this.step % 4 === 2) { - this.playWobble(now); - } - - this.step++; - } - - private playNote(freq: number, time: number, duration: number, type: OscillatorType, volume: number) { - if (!this.audioContext || !this.masterGain) return; - - const osc = this.audioContext.createOscillator(); - const gain = this.audioContext.createGain(); - - osc.type = type; - osc.frequency.value = freq; - - gain.gain.setValueAtTime(volume, time); - gain.gain.exponentialRampToValueAtTime(0.001, time + duration); - - osc.connect(gain); - gain.connect(this.masterGain); - - osc.start(time); - osc.stop(time + duration); - } - - private playDrum(time: number, type: "kick" | "hihat" | "snare" = "hihat") { - if (!this.audioContext || !this.masterGain) return; - - if (type === "kick") { - // Heavy dubstep kick - deep and punchy - const osc = this.audioContext.createOscillator(); - const gain = this.audioContext.createGain(); - - osc.type = "sine"; - osc.frequency.setValueAtTime(180, time); - osc.frequency.exponentialRampToValueAtTime(30, time + 0.12); - - gain.gain.setValueAtTime(0.5, time); - gain.gain.exponentialRampToValueAtTime(0.001, time + 0.2); - - osc.connect(gain); - gain.connect(this.masterGain); - - osc.start(time); - osc.stop(time + 0.2); - - // Add click for attack - const click = this.audioContext.createOscillator(); - const clickGain = this.audioContext.createGain(); - click.type = "square"; - click.frequency.value = 800; - clickGain.gain.setValueAtTime(0.15, time); - clickGain.gain.exponentialRampToValueAtTime(0.001, time + 0.02); - click.connect(clickGain); - clickGain.connect(this.masterGain); - click.start(time); - click.stop(time + 0.02); - - } else if (type === "snare") { - // Aggressive dubstep snare - noise + tone - const bufferSize = this.audioContext.sampleRate * 0.15; - const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate); - const data = buffer.getChannelData(0); - - for (let i = 0; i < bufferSize; i++) { - data[i] = Math.random() * 2 - 1; - } - - const noise = this.audioContext.createBufferSource(); - noise.buffer = buffer; - - const noiseGain = this.audioContext.createGain(); - noiseGain.gain.setValueAtTime(0.3, time); - noiseGain.gain.exponentialRampToValueAtTime(0.001, time + 0.15); - - const filter = this.audioContext.createBiquadFilter(); - filter.type = "bandpass"; - filter.frequency.value = 3000; - filter.Q.value = 1; - - noise.connect(filter); - filter.connect(noiseGain); - noiseGain.connect(this.masterGain); - - noise.start(time); - noise.stop(time + 0.15); - - // Add tone body - const tone = this.audioContext.createOscillator(); - const toneGain = this.audioContext.createGain(); - tone.type = "triangle"; - tone.frequency.setValueAtTime(200, time); - tone.frequency.exponentialRampToValueAtTime(100, time + 0.05); - toneGain.gain.setValueAtTime(0.2, time); - toneGain.gain.exponentialRampToValueAtTime(0.001, time + 0.08); - tone.connect(toneGain); - toneGain.connect(this.masterGain); - tone.start(time); - tone.stop(time + 0.08); - + if (isPlaying && hasInteracted) { + audioRef.current.play().catch(() => { + // Autoplay blocked, will retry on user interaction + }); } else { - // Hi-hat - crispy noise - const bufferSize = this.audioContext.sampleRate * 0.04; - const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate); - const data = buffer.getChannelData(0); - - for (let i = 0; i < bufferSize; i++) { - data[i] = Math.random() * 2 - 1; + audioRef.current.pause(); + } + }, [isPlaying, hasInteracted]); + + // Listen for first user interaction to enable autoplay + useEffect(() => { + const handleInteraction = () => { + setHasInteracted(true); + if (isPlaying && audioRef.current) { + audioRef.current.play().catch(() => {}); } - - const noise = this.audioContext.createBufferSource(); - noise.buffer = buffer; - - const gain = this.audioContext.createGain(); - gain.gain.setValueAtTime(0.08, time); - gain.gain.exponentialRampToValueAtTime(0.001, time + 0.04); - - const filter = this.audioContext.createBiquadFilter(); - filter.type = "highpass"; - filter.frequency.value = 9000; - - noise.connect(filter); - filter.connect(gain); - gain.connect(this.masterGain); - - noise.start(time); - noise.stop(time + 0.04); - } - } + }; - private playWobble(time: number) { - if (!this.audioContext || !this.masterGain) return; + document.addEventListener("click", handleInteraction, { once: true }); + document.addEventListener("keydown", handleInteraction, { once: true }); + document.addEventListener("touchstart", handleInteraction, { once: true }); - // Classic dubstep wobble bass - const osc = this.audioContext.createOscillator(); - const gain = this.audioContext.createGain(); - const lfo = this.audioContext.createOscillator(); - const lfoGain = this.audioContext.createGain(); - - osc.type = "sawtooth"; - osc.frequency.value = 55; // Low A - - // LFO for wobble effect - lfo.type = "sine"; - lfo.frequency.value = 8; // Wobble speed - lfoGain.gain.value = 400; - - lfo.connect(lfoGain); - - // Create filter for wobble - const filter = this.audioContext.createBiquadFilter(); - filter.type = "lowpass"; - filter.frequency.value = 400; - filter.Q.value = 8; - - lfoGain.connect(filter.frequency); - - gain.gain.setValueAtTime(0.2, time); - gain.gain.exponentialRampToValueAtTime(0.001, time + 0.3); - - osc.connect(filter); - filter.connect(gain); - gain.connect(this.masterGain); - - lfo.start(time); - osc.start(time); - lfo.stop(time + 0.3); - osc.stop(time + 0.3); - } + return () => { + document.removeEventListener("click", handleInteraction); + document.removeEventListener("keydown", handleInteraction); + document.removeEventListener("touchstart", handleInteraction); + }; + }, [isPlaying]); - stop() { - if (this.intervalId) { - clearInterval(this.intervalId); - this.intervalId = null; - } - if (this.audioContext) { - this.audioContext.close(); - this.audioContext = null; - } - this.isPlaying = false; - } - - getIsPlaying() { - return this.isPlaying; - } + return ( + + {children} + + ); } export function MusicButton() { - const [isPlaying, setIsPlaying] = useState(false); - const playerRef = useRef(null); + const context = useMusicContext(); + + // Fallback for when not wrapped in provider + const [localPlaying, setLocalPlaying] = useState(false); + const localAudioRef = useRef(null); + + const isPlaying = context?.isPlaying ?? localPlaying; + const setIsPlaying = context?.setIsPlaying ?? setLocalPlaying; - const toggleMusic = useCallback(async () => { - if (!playerRef.current) { - playerRef.current = new ChiptunePlayer(); - } - - if (isPlaying) { - playerRef.current.stop(); - setIsPlaying(false); + const toggleMusic = useCallback(() => { + if (context) { + context.setIsPlaying(!context.isPlaying); } else { - await playerRef.current.start(); - setIsPlaying(true); + // Fallback behavior + if (!localAudioRef.current) { + localAudioRef.current = new Audio("/kids-music.mp3"); + localAudioRef.current.loop = true; + localAudioRef.current.volume = 0.3; + } + + if (localPlaying) { + localAudioRef.current.pause(); + setLocalPlaying(false); + } else { + localAudioRef.current.play().catch(() => {}); + setLocalPlaying(true); + } } - }, [isPlaying]); + }, [context, localPlaying]); return ( + + setIsPlaying(!isPlaying)} + className={`px-3 py-1.5 rounded-lg font-medium text-sm transition-colors ${ + isPlaying + ? "bg-[#22C55E] text-white" + : "bg-gray-200 text-gray-600" + }`} + > + {isPlaying ? "🔊 On" : "🔇 Off"} + + {Math.round(volume * 100)}% + + setVolume(parseInt(e.target.value) / 100)} + className="w-full h-2 bg-[#D4A574] rounded-lg appearance-none cursor-pointer accent-[#8B4513]" + /> + + ); +} + // Legacy export for backwards compatibility export function BackgroundMusic() { return null; diff --git a/src/components/kids/layout/settings-modal.tsx b/src/components/kids/layout/settings-modal.tsx index e61ade7c..6185a936 100644 --- a/src/components/kids/layout/settings-modal.tsx +++ b/src/components/kids/layout/settings-modal.tsx @@ -6,7 +6,8 @@ import { cn } from "@/lib/utils"; import { clearAllProgress, getTotalStars, getCompletedLevelsCount } from "@/lib/kids/progress"; import { setLocale } from "@/lib/i18n/client"; import { analyticsKids } from "@/lib/analytics"; -import { Settings, X, Globe, Trash2, Check } from "lucide-react"; +import { Settings, X, Globe, Trash2, Check, Volume2 } from "lucide-react"; +import { MusicVolumeSlider } from "./background-music"; const SUPPORTED_LOCALES = [ { code: "en", label: "English", flag: "🇺🇸" }, @@ -91,7 +92,7 @@ function SettingsModal({ onClose }: { onClose: () => void }) { /> {/* Modal */} - + {/* Close button */} void }) { {t("title")} + {/* Music Section */} + + + + {t("music")} + + + + Music by{" "} + + Krzysztof Szymanski + {" "} + from{" "} + + Pixabay + + + + {/* Language Section */}
+ Music by{" "} + + Krzysztof Szymanski + {" "} + from{" "} + + Pixabay + +