diff --git a/.git-credentials b/.git-credentials
new file mode 100644
index 0000000..d78ec0a
--- /dev/null
+++ b/.git-credentials
@@ -0,0 +1,2 @@
+http://sultanbek_askaruly:ccaf3980723058bd093e312780c167c82b9a54e6@172.18.0.1%3a3300
+https://sultanbek_askaruly:ccaf3980723058bd093e312780c167c82b9a54e6@git.vibe42.kz
diff --git a/contact.html b/contact.html
index c1c142b..10a8fe9 100644
--- a/contact.html
+++ b/contact.html
@@ -20,6 +20,7 @@
Exercises
Tests
Reading
+ Progress
Contact
diff --git a/css/style.css b/css/style.css
index 880bc8f..88b6daf 100644
--- a/css/style.css
+++ b/css/style.css
@@ -1014,6 +1014,167 @@ footer a:hover {
}
}
+/* ===== PROGRESS PAGE ===== */
+.level-hero {
+ text-align: center;
+ padding: 48px 32px;
+ background: linear-gradient(135deg, var(--accent-50), var(--green-light));
+ border-radius: 24px;
+ margin-bottom: 32px;
+}
+
+.level-hero .level-icon {
+ font-size: 56px;
+ margin-bottom: 12px;
+}
+
+.level-hero .level-title {
+ font-size: 36px;
+ font-weight: 800;
+ color: var(--accent);
+ margin-bottom: 4px;
+}
+
+.level-hero .level-desc {
+ font-size: 16px;
+ color: var(--gray-500);
+ margin-bottom: 20px;
+}
+
+.level-hero .level-xp-total {
+ font-size: 20px;
+ font-weight: 700;
+ color: var(--ink);
+}
+
+.level-bar {
+ height: 12px;
+ background: var(--gray-100);
+ border-radius: 6px;
+ overflow: hidden;
+ max-width: 400px;
+ margin: 12px auto 0;
+}
+
+.level-bar-fill {
+ height: 100%;
+ background: linear-gradient(90deg, var(--accent), var(--green));
+ border-radius: 6px;
+ transition: width 0.6s ease;
+ width: 0%;
+}
+
+.stat-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
+ gap: 16px;
+ margin-bottom: 32px;
+}
+
+.stat-card {
+ background: var(--white);
+ border: 1px solid var(--gray-100);
+ border-radius: 16px;
+ padding: 24px;
+ text-align: center;
+ box-shadow: var(--shadow);
+ transition: all 0.3s;
+}
+
+.stat-card:hover {
+ transform: translateY(-3px);
+ box-shadow: var(--shadow-hover);
+}
+
+.stat-card .stat-icon {
+ font-size: 28px;
+ margin-bottom: 8px;
+}
+
+.stat-card .stat-value {
+ font-size: 28px;
+ font-weight: 800;
+ color: var(--accent);
+}
+
+.stat-card .stat-label {
+ font-size: 13px;
+ color: var(--gray-500);
+ margin-top: 4px;
+}
+
+.activity-list {
+ background: var(--white);
+ border: 1px solid var(--gray-100);
+ border-radius: 20px;
+ padding: 28px;
+ box-shadow: var(--shadow);
+}
+
+.activity-list h3 {
+ font-size: 20px;
+ font-weight: 700;
+ margin-bottom: 16px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.activity-item {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 12px 0;
+ border-bottom: 1px solid var(--gray-100);
+ font-size: 15px;
+}
+
+.activity-item:last-child {
+ border-bottom: none;
+}
+
+.activity-item .act-icon {
+ width: 36px;
+ height: 36px;
+ background: var(--accent-50);
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 16px;
+ flex-shrink: 0;
+}
+
+.activity-item .act-text {
+ flex: 1;
+ color: var(--gray-500);
+}
+
+.activity-item .act-xp {
+ font-weight: 700;
+ color: var(--green);
+ font-size: 14px;
+}
+
+.level-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ background: var(--accent-50);
+ padding: 6px 16px 6px 12px;
+ border-radius: 20px;
+ font-size: 13px;
+}
+
+.level-badge .level-label {
+ font-weight: 700;
+ color: var(--accent);
+}
+
+.level-badge .level-xp {
+ color: var(--gray-500);
+}
+
/* ===== ANIMATIONS ===== */
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(20px); }
diff --git a/exercises.html b/exercises.html
index 2e3aef0..821aba9 100644
--- a/exercises.html
+++ b/exercises.html
@@ -20,6 +20,7 @@
Exercises
Tests
Reading
+ Progress
Contact
diff --git a/grammar.html b/grammar.html
index 164f3ea..c6bb1c7 100644
--- a/grammar.html
+++ b/grammar.html
@@ -20,6 +20,7 @@
Exercises
Tests
Reading
+ Progress
Contact
diff --git a/index.html b/index.html
index 7ef746f..d57cbeb 100644
--- a/index.html
+++ b/index.html
@@ -20,6 +20,7 @@
Exercises
Tests
Reading
+ Progress
Contact
@@ -79,6 +80,12 @@
Listen to words and phrases spoken aloud. Practice your pronunciation and improve your speaking skills.
Start Speaking
+
+
📊
+
My Progress
+
Track your XP, level, and completed activities. Watch yourself improve from Beginner to Advanced!
+
View Progress
+
diff --git a/js/script.js b/js/script.js
index dbbc8ab..54c6bb5 100644
--- a/js/script.js
+++ b/js/script.js
@@ -50,13 +50,14 @@ function checkExercise(btn) {
if (isCorrect) {
parent.classList.add('correct');
- feedback.textContent = 'Correct!';
+ feedback.textContent = 'Correct! +10 XP';
feedback.className = 'feedback correct';
+ var exId = exercise.getAttribute('data-ex-id') || exercise.querySelector('h3').textContent.trim();
+ markExerciseDone(exId);
} else {
parent.classList.add('wrong');
feedback.textContent = 'Try again!';
feedback.className = 'feedback wrong';
- // Show correct answer
options.forEach(function(opt) {
const radio = opt.querySelector('input[type="radio"]');
if (radio && radio.value === 'true') {
@@ -76,8 +77,10 @@ function checkFill(input) {
if (input.value.trim().toLowerCase() === answer.toLowerCase()) {
input.classList.add('correct');
- feedback.textContent = 'Correct!';
+ feedback.textContent = 'Correct! +10 XP';
feedback.className = 'feedback correct';
+ var exId = input.closest('.exercise').getAttribute('data-ex-id') || input.closest('.exercise').querySelector('h3').textContent.trim();
+ markExerciseDone(exId);
} else {
input.classList.add('wrong');
feedback.textContent = 'Try again! Correct answer: ' + answer;
@@ -96,8 +99,10 @@ function checkTranslate(btn) {
if (input.value.trim().toLowerCase() === answer.toLowerCase()) {
input.classList.add('correct');
- feedback.textContent = 'Correct!';
+ feedback.textContent = 'Correct! +10 XP';
feedback.className = 'feedback correct';
+ var exId = exercise.getAttribute('data-ex-id') || exercise.querySelector('h3').textContent.trim();
+ markExerciseDone(exId);
} else {
input.classList.add('wrong');
feedback.textContent = 'Try again! Correct answer: ' + answer;
@@ -124,8 +129,10 @@ function checkMatch(btn) {
});
if (allCorrect) {
- feedback.textContent = 'All correct! Great job!';
+ feedback.textContent = 'All correct! Great job! +10 XP';
feedback.className = 'feedback correct';
+ var exId = exercise.getAttribute('data-ex-id') || exercise.querySelector('h3').textContent.trim();
+ markExerciseDone(exId);
} else {
feedback.textContent = 'Some answers are wrong. Try again!';
feedback.className = 'feedback wrong';
@@ -146,12 +153,21 @@ function checkTest() {
}
});
+ markTestDone(score, total);
+
+ var data = getProgress();
+ var info = getLevelProgress(data.xp);
+
const resultBox = document.getElementById('test-result');
const scoreDisplay = document.getElementById('score');
scoreDisplay.textContent = score + '/' + total;
resultBox.classList.add('show');
- // Scroll to result
+ var detail = document.getElementById('test-detail');
+ if (detail) {
+ detail.innerHTML = 'Level: ' + info.current.label + ' | XP: ' + data.xp + ' | Best: ' + data.bestTestScore + '/' + total + '';
+ }
+
resultBox.scrollIntoView({ behavior: 'smooth' });
}
@@ -184,6 +200,7 @@ function repeatWord(btn) {
var word = btn.getAttribute('data-word');
speakWord(word, 0.8);
btn.textContent = '🔊 Playing...';
+ markWordListened();
setTimeout(function() { btn.textContent = '🔊 Listen'; }, 1500);
}
@@ -220,6 +237,107 @@ function speakPhrase(btn) {
setTimeout(function() { btn.innerHTML = '🔊 Hear Phrase'; }, 1500);
}
+// --- Progress Tracking ---
+var PROGRESS_KEY = 'english_easy_progress';
+
+var LEVELS = [
+ { min: 0, label: 'A0 Beginner', desc: 'You are just starting your English journey!' },
+ { min: 50, label: 'A1 Starter', desc: 'You know basic words and phrases.' },
+ { min: 150, label: 'A2 Elementary', desc: 'You can understand simple sentences.' },
+ { min: 300, label: 'B1 Intermediate', desc: 'You can talk about familiar topics.' },
+ { min: 500, label: 'B2 Upper Intermediate', desc: 'You can communicate fluently.' },
+ { min: 800, label: 'C1 Advanced', desc: 'You understand complex texts and ideas.' }
+];
+
+function getProgress() {
+ var data = JSON.parse(localStorage.getItem(PROGRESS_KEY));
+ if (!data) {
+ data = {
+ xp: 0,
+ exercisesDone: [],
+ testsDone: 0,
+ bestTestScore: 0,
+ lastTestScore: 0,
+ wordsListened: 0,
+ readingDone: [],
+ joined: new Date().toISOString().split('T')[0]
+ };
+ localStorage.setItem(PROGRESS_KEY, JSON.stringify(data));
+ }
+ return data;
+}
+
+function saveProgress(data) {
+ localStorage.setItem(PROGRESS_KEY, JSON.stringify(data));
+}
+
+function addXP(amount, reason) {
+ var data = getProgress();
+ data.xp += amount;
+ saveProgress(data);
+ updateLevelBadge();
+ return data;
+}
+
+function getLevel(xp) {
+ for (var i = LEVELS.length - 1; i >= 0; i--) {
+ if (xp >= LEVELS[i].min) return LEVELS[i];
+ }
+ return LEVELS[0];
+}
+
+function getLevelProgress(xp) {
+ var current = getLevel(xp);
+ var nextMin = 9999;
+ for (var i = 0; i < LEVELS.length; i++) {
+ if (LEVELS[i].min > current.min) {
+ nextMin = LEVELS[i].min;
+ break;
+ }
+ }
+ var range = nextMin - current.min;
+ var progress = xp - current.min;
+ return { current: current, nextMin: nextMin, progress: progress, range: range, percent: range > 0 ? Math.min(100, Math.round(progress / range * 100)) : 100 };
+}
+
+function updateLevelBadge() {
+ var data = getProgress();
+ var info = getLevelProgress(data.xp);
+ var badge = document.querySelector('.level-badge');
+ if (badge) {
+ badge.innerHTML = '' + info.current.label + '' + data.xp + ' XP';
+ }
+ var bar = document.querySelector('.level-bar-fill');
+ if (bar) bar.style.width = info.percent + '%';
+}
+
+function markExerciseDone(id) {
+ var data = getProgress();
+ if (data.exercisesDone.indexOf(id) === -1) {
+ data.exercisesDone.push(id);
+ data.xp += 10;
+ saveProgress(data);
+ }
+}
+
+function markTestDone(score, total) {
+ var data = getProgress();
+ data.testsDone++;
+ data.lastTestScore = score;
+ if (score > data.bestTestScore) data.bestTestScore = score;
+ data.xp += 15 + score * 2;
+ saveProgress(data);
+}
+
+function markWordListened() {
+ var data = getProgress();
+ data.wordsListened++;
+ if (data.wordsListened % 5 === 0) {
+ data.xp += 5;
+ saveProgress(data);
+ }
+}
+
// --- Daily Reminder at 20:00 ---
(function() {
var LS_KEY = 'english_easy_daily';
diff --git a/progress.html b/progress.html
new file mode 100644
index 0000000..734f144
--- /dev/null
+++ b/progress.html
@@ -0,0 +1,150 @@
+
+
+
+
+
+ My Progress — English Easy
+
+
+
+
+
+
+
+
+
+
+
+
🌱
+
A0 Beginner
+
You are just starting your English journey!
+
0 XP
+
+
+
+
+
+
✅
+
0
+
Exercises Done
+
+
+
+
🏆
+
—
+
Best Test Score
+
+
+
🔊
+
0
+
Words Practiced
+
+
+
+
+
📋 Recent Activity
+
+
👋
Start learning to see your activity here!
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pronunciation.html b/pronunciation.html
index 477af3b..9903bf8 100644
--- a/pronunciation.html
+++ b/pronunciation.html
@@ -117,6 +117,7 @@
Exercises
Tests
Reading
+ Progress
Contact
diff --git a/reading.html b/reading.html
index a040e85..629ae8d 100644
--- a/reading.html
+++ b/reading.html
@@ -20,6 +20,7 @@
Exercises
Tests
Reading
+ Progress
Contact
diff --git a/tests.html b/tests.html
index a6b9b56..39da83b 100644
--- a/tests.html
+++ b/tests.html
@@ -20,6 +20,7 @@
Exercises
Tests
Reading
+ Progress
Contact
@@ -132,7 +133,7 @@
0/10
-
Keep learning and try again!
+
Keep learning and try again!
diff --git a/vocabulary.html b/vocabulary.html
index 74af830..071f63a 100644
--- a/vocabulary.html
+++ b/vocabulary.html
@@ -20,6 +20,7 @@
Exercises
Tests
Reading
+ Progress
Contact