add progress tracking with XP, levels, and stats dashboard
This commit is contained in:
parent
c5bec7fed6
commit
69f0d9f78b
2
.git-credentials
Normal file
2
.git-credentials
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
http://sultanbek_askaruly:ccaf3980723058bd093e312780c167c82b9a54e6@172.18.0.1%3a3300
|
||||||
|
https://sultanbek_askaruly:ccaf3980723058bd093e312780c167c82b9a54e6@git.vibe42.kz
|
||||||
@ -20,6 +20,7 @@
|
|||||||
<li><a href="exercises.html">Exercises</a></li>
|
<li><a href="exercises.html">Exercises</a></li>
|
||||||
<li><a href="tests.html">Tests</a></li>
|
<li><a href="tests.html">Tests</a></li>
|
||||||
<li><a href="reading.html">Reading</a></li>
|
<li><a href="reading.html">Reading</a></li>
|
||||||
|
<li><a href="progress.html">Progress</a></li>
|
||||||
<li><a href="contact.html">Contact</a></li>
|
<li><a href="contact.html">Contact</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
161
css/style.css
161
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 ===== */
|
/* ===== ANIMATIONS ===== */
|
||||||
@keyframes fadeInUp {
|
@keyframes fadeInUp {
|
||||||
from { opacity: 0; transform: translateY(20px); }
|
from { opacity: 0; transform: translateY(20px); }
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
<li><a href="exercises.html">Exercises</a></li>
|
<li><a href="exercises.html">Exercises</a></li>
|
||||||
<li><a href="tests.html">Tests</a></li>
|
<li><a href="tests.html">Tests</a></li>
|
||||||
<li><a href="reading.html">Reading</a></li>
|
<li><a href="reading.html">Reading</a></li>
|
||||||
|
<li><a href="progress.html">Progress</a></li>
|
||||||
<li><a href="contact.html">Contact</a></li>
|
<li><a href="contact.html">Contact</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
<li><a href="exercises.html">Exercises</a></li>
|
<li><a href="exercises.html">Exercises</a></li>
|
||||||
<li><a href="tests.html">Tests</a></li>
|
<li><a href="tests.html">Tests</a></li>
|
||||||
<li><a href="reading.html">Reading</a></li>
|
<li><a href="reading.html">Reading</a></li>
|
||||||
|
<li><a href="progress.html">Progress</a></li>
|
||||||
<li><a href="contact.html">Contact</a></li>
|
<li><a href="contact.html">Contact</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
<li><a href="exercises.html">Exercises</a></li>
|
<li><a href="exercises.html">Exercises</a></li>
|
||||||
<li><a href="tests.html">Tests</a></li>
|
<li><a href="tests.html">Tests</a></li>
|
||||||
<li><a href="reading.html">Reading</a></li>
|
<li><a href="reading.html">Reading</a></li>
|
||||||
|
<li><a href="progress.html">Progress</a></li>
|
||||||
<li><a href="contact.html">Contact</a></li>
|
<li><a href="contact.html">Contact</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
@ -79,6 +80,12 @@
|
|||||||
<p>Listen to words and phrases spoken aloud. Practice your pronunciation and improve your speaking skills.</p>
|
<p>Listen to words and phrases spoken aloud. Practice your pronunciation and improve your speaking skills.</p>
|
||||||
<a href="pronunciation.html" class="btn btn-primary">Start Speaking</a>
|
<a href="pronunciation.html" class="btn btn-primary">Start Speaking</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-icon">📊</div>
|
||||||
|
<h3>My Progress</h3>
|
||||||
|
<p>Track your XP, level, and completed activities. Watch yourself improve from Beginner to Advanced!</p>
|
||||||
|
<a href="progress.html" class="btn btn-primary">View Progress</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
130
js/script.js
130
js/script.js
@ -50,13 +50,14 @@ function checkExercise(btn) {
|
|||||||
|
|
||||||
if (isCorrect) {
|
if (isCorrect) {
|
||||||
parent.classList.add('correct');
|
parent.classList.add('correct');
|
||||||
feedback.textContent = 'Correct!';
|
feedback.textContent = 'Correct! +10 XP';
|
||||||
feedback.className = 'feedback correct';
|
feedback.className = 'feedback correct';
|
||||||
|
var exId = exercise.getAttribute('data-ex-id') || exercise.querySelector('h3').textContent.trim();
|
||||||
|
markExerciseDone(exId);
|
||||||
} else {
|
} else {
|
||||||
parent.classList.add('wrong');
|
parent.classList.add('wrong');
|
||||||
feedback.textContent = 'Try again!';
|
feedback.textContent = 'Try again!';
|
||||||
feedback.className = 'feedback wrong';
|
feedback.className = 'feedback wrong';
|
||||||
// Show correct answer
|
|
||||||
options.forEach(function(opt) {
|
options.forEach(function(opt) {
|
||||||
const radio = opt.querySelector('input[type="radio"]');
|
const radio = opt.querySelector('input[type="radio"]');
|
||||||
if (radio && radio.value === 'true') {
|
if (radio && radio.value === 'true') {
|
||||||
@ -76,8 +77,10 @@ function checkFill(input) {
|
|||||||
|
|
||||||
if (input.value.trim().toLowerCase() === answer.toLowerCase()) {
|
if (input.value.trim().toLowerCase() === answer.toLowerCase()) {
|
||||||
input.classList.add('correct');
|
input.classList.add('correct');
|
||||||
feedback.textContent = 'Correct!';
|
feedback.textContent = 'Correct! +10 XP';
|
||||||
feedback.className = 'feedback correct';
|
feedback.className = 'feedback correct';
|
||||||
|
var exId = input.closest('.exercise').getAttribute('data-ex-id') || input.closest('.exercise').querySelector('h3').textContent.trim();
|
||||||
|
markExerciseDone(exId);
|
||||||
} else {
|
} else {
|
||||||
input.classList.add('wrong');
|
input.classList.add('wrong');
|
||||||
feedback.textContent = 'Try again! Correct answer: ' + answer;
|
feedback.textContent = 'Try again! Correct answer: ' + answer;
|
||||||
@ -96,8 +99,10 @@ function checkTranslate(btn) {
|
|||||||
|
|
||||||
if (input.value.trim().toLowerCase() === answer.toLowerCase()) {
|
if (input.value.trim().toLowerCase() === answer.toLowerCase()) {
|
||||||
input.classList.add('correct');
|
input.classList.add('correct');
|
||||||
feedback.textContent = 'Correct!';
|
feedback.textContent = 'Correct! +10 XP';
|
||||||
feedback.className = 'feedback correct';
|
feedback.className = 'feedback correct';
|
||||||
|
var exId = exercise.getAttribute('data-ex-id') || exercise.querySelector('h3').textContent.trim();
|
||||||
|
markExerciseDone(exId);
|
||||||
} else {
|
} else {
|
||||||
input.classList.add('wrong');
|
input.classList.add('wrong');
|
||||||
feedback.textContent = 'Try again! Correct answer: ' + answer;
|
feedback.textContent = 'Try again! Correct answer: ' + answer;
|
||||||
@ -124,8 +129,10 @@ function checkMatch(btn) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (allCorrect) {
|
if (allCorrect) {
|
||||||
feedback.textContent = 'All correct! Great job!';
|
feedback.textContent = 'All correct! Great job! +10 XP';
|
||||||
feedback.className = 'feedback correct';
|
feedback.className = 'feedback correct';
|
||||||
|
var exId = exercise.getAttribute('data-ex-id') || exercise.querySelector('h3').textContent.trim();
|
||||||
|
markExerciseDone(exId);
|
||||||
} else {
|
} else {
|
||||||
feedback.textContent = 'Some answers are wrong. Try again!';
|
feedback.textContent = 'Some answers are wrong. Try again!';
|
||||||
feedback.className = 'feedback wrong';
|
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 resultBox = document.getElementById('test-result');
|
||||||
const scoreDisplay = document.getElementById('score');
|
const scoreDisplay = document.getElementById('score');
|
||||||
scoreDisplay.textContent = score + '/' + total;
|
scoreDisplay.textContent = score + '/' + total;
|
||||||
resultBox.classList.add('show');
|
resultBox.classList.add('show');
|
||||||
|
|
||||||
// Scroll to result
|
var detail = document.getElementById('test-detail');
|
||||||
|
if (detail) {
|
||||||
|
detail.innerHTML = 'Level: <strong>' + info.current.label + '</strong> | XP: <strong>' + data.xp + '</strong> | Best: <strong>' + data.bestTestScore + '/' + total + '</strong>';
|
||||||
|
}
|
||||||
|
|
||||||
resultBox.scrollIntoView({ behavior: 'smooth' });
|
resultBox.scrollIntoView({ behavior: 'smooth' });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,6 +200,7 @@ function repeatWord(btn) {
|
|||||||
var word = btn.getAttribute('data-word');
|
var word = btn.getAttribute('data-word');
|
||||||
speakWord(word, 0.8);
|
speakWord(word, 0.8);
|
||||||
btn.textContent = '🔊 Playing...';
|
btn.textContent = '🔊 Playing...';
|
||||||
|
markWordListened();
|
||||||
setTimeout(function() { btn.textContent = '🔊 Listen'; }, 1500);
|
setTimeout(function() { btn.textContent = '🔊 Listen'; }, 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +237,107 @@ function speakPhrase(btn) {
|
|||||||
setTimeout(function() { btn.innerHTML = '🔊 Hear Phrase'; }, 1500);
|
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 = '<span class="level-label">' + info.current.label + '</span><span class="level-xp">' + data.xp + ' XP</span>';
|
||||||
|
}
|
||||||
|
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 ---
|
// --- Daily Reminder at 20:00 ---
|
||||||
(function() {
|
(function() {
|
||||||
var LS_KEY = 'english_easy_daily';
|
var LS_KEY = 'english_easy_daily';
|
||||||
|
|||||||
150
progress.html
Normal file
150
progress.html
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>My Progress — English Easy</title>
|
||||||
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="header-inner">
|
||||||
|
<a href="index.html" class="logo"><span class="logo-icon">E</span>English <span>Easy</span></a>
|
||||||
|
<button class="menu-toggle" aria-label="Menu">☰</button>
|
||||||
|
<nav>
|
||||||
|
<ul class="nav-list">
|
||||||
|
<li><a href="index.html">Home</a></li>
|
||||||
|
<li><a href="vocabulary.html">Vocabulary</a></li>
|
||||||
|
<li><a href="grammar.html">Grammar</a></li>
|
||||||
|
<li><a href="pronunciation.html">Pronunciation</a></li>
|
||||||
|
<li><a href="exercises.html">Exercises</a></li>
|
||||||
|
<li><a href="tests.html">Tests</a></li>
|
||||||
|
<li><a href="reading.html">Reading</a></li>
|
||||||
|
<li><a href="progress.html">Progress</a></li>
|
||||||
|
<li><a href="contact.html">Contact</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="page-header">
|
||||||
|
<div class="container">
|
||||||
|
<h1>My Progress</h1>
|
||||||
|
<p>Track your learning journey and see how much you've achieved.</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<div class="container" id="progress-root">
|
||||||
|
|
||||||
|
<div class="level-hero" id="level-hero">
|
||||||
|
<div class="level-icon" id="level-icon">🌱</div>
|
||||||
|
<div class="level-title" id="level-title">A0 Beginner</div>
|
||||||
|
<div class="level-desc" id="level-desc">You are just starting your English journey!</div>
|
||||||
|
<div class="level-xp-total" id="level-xp-total">0 XP</div>
|
||||||
|
<div class="level-bar"><div class="level-bar-fill" id="level-bar-fill" style="width:0%"></div></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat-grid" id="stats-grid">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-icon">✅</div>
|
||||||
|
<div class="stat-value" id="stat-exercises">0</div>
|
||||||
|
<div class="stat-label">Exercises Done</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-icon">📝</div>
|
||||||
|
<div class="stat-value" id="stat-tests">0</div>
|
||||||
|
<div class="stat-label">Tests Taken</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-icon">🏆</div>
|
||||||
|
<div class="stat-value" id="stat-best">—</div>
|
||||||
|
<div class="stat-label">Best Test Score</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-icon">🔊</div>
|
||||||
|
<div class="stat-value" id="stat-words">0</div>
|
||||||
|
<div class="stat-label">Words Practiced</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="activity-list">
|
||||||
|
<h3>📋 Recent Activity</h3>
|
||||||
|
<div id="activity-feed">
|
||||||
|
<div class="activity-item"><div class="act-icon">👋</div><div class="act-text">Start learning to see your activity here!</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="container">
|
||||||
|
<p>© 2026 <a href="index.html">English Easy</a>. Made for learning English.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="js/script.js"></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
renderProgress();
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderProgress() {
|
||||||
|
var data = getProgress();
|
||||||
|
var info = getLevelProgress(data.xp);
|
||||||
|
|
||||||
|
var icons = ['🌱', '🌿', '🌳', '⭐', '🌟', '👑'];
|
||||||
|
var levelIndex = LEVELS.indexOf(info.current);
|
||||||
|
document.getElementById('level-icon').textContent = icons[levelIndex] || '🌱';
|
||||||
|
document.getElementById('level-title').textContent = info.current.label;
|
||||||
|
document.getElementById('level-desc').textContent = info.current.desc;
|
||||||
|
document.getElementById('level-xp-total').textContent = data.xp + ' XP';
|
||||||
|
document.getElementById('level-bar-fill').style.width = info.percent + '%';
|
||||||
|
|
||||||
|
document.getElementById('stat-exercises').textContent = data.exercisesDone.length;
|
||||||
|
document.getElementById('stat-tests').textContent = data.testsDone;
|
||||||
|
document.getElementById('stat-best').textContent = data.bestTestScore > 0 ? data.bestTestScore + '/10' : '—';
|
||||||
|
document.getElementById('stat-words').textContent = data.wordsListened;
|
||||||
|
|
||||||
|
// Activity feed
|
||||||
|
var feed = document.getElementById('activity-feed');
|
||||||
|
feed.innerHTML = '';
|
||||||
|
var activities = [];
|
||||||
|
|
||||||
|
if (data.exercisesDone.length > 0) {
|
||||||
|
activities.push({ icon: '✅', text: 'Completed ' + data.exercisesDone.length + ' exercise' + (data.exercisesDone.length > 1 ? 's' : ''), xp: data.exercisesDone.length * 10 });
|
||||||
|
}
|
||||||
|
if (data.testsDone > 0) {
|
||||||
|
activities.push({ icon: '📝', text: 'Took ' + data.testsDone + ' test' + (data.testsDone > 1 ? 's' : ''), xp: 15 + data.bestTestScore * 2 });
|
||||||
|
}
|
||||||
|
if (data.wordsListened > 0) {
|
||||||
|
activities.push({ icon: '🔊', text: 'Practiced ' + data.wordsListened + ' word' + (data.wordsListened > 1 ? 's' : '') + ' with pronunciation', xp: Math.floor(data.wordsListened / 5) * 5 });
|
||||||
|
}
|
||||||
|
if (data.readingDone && data.readingDone.length > 0) {
|
||||||
|
activities.push({ icon: '📚', text: 'Read ' + data.readingDone.length + ' text' + (data.readingDone.length > 1 ? 's' : ''), xp: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activities.length === 0) {
|
||||||
|
feed.innerHTML = '<div class="activity-item"><div class="act-icon">👋</div><div class="act-text">Complete exercises and tests to see your activity here!</div></div>';
|
||||||
|
} else {
|
||||||
|
activities.forEach(function(a) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.className = 'activity-item';
|
||||||
|
div.innerHTML = '<div class="act-icon">' + a.icon + '</div><div class="act-text">' + a.text + '</div><div class="act-xp">+' + a.xp + ' XP</div>';
|
||||||
|
feed.appendChild(div);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Total
|
||||||
|
var totalDiv = document.createElement('div');
|
||||||
|
totalDiv.className = 'activity-item';
|
||||||
|
totalDiv.style.borderTop = '2px solid var(--gray-100)';
|
||||||
|
totalDiv.style.paddingTop = '16px';
|
||||||
|
totalDiv.style.marginTop = '8px';
|
||||||
|
totalDiv.innerHTML = '<div class="act-icon">⭐</div><div class="act-text"><strong>Total XP</strong></div><div class="act-xp" style="font-size:18px;">' + data.xp + ' XP</div>';
|
||||||
|
feed.appendChild(totalDiv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -117,6 +117,7 @@
|
|||||||
<li><a href="exercises.html">Exercises</a></li>
|
<li><a href="exercises.html">Exercises</a></li>
|
||||||
<li><a href="tests.html">Tests</a></li>
|
<li><a href="tests.html">Tests</a></li>
|
||||||
<li><a href="reading.html">Reading</a></li>
|
<li><a href="reading.html">Reading</a></li>
|
||||||
|
<li><a href="progress.html">Progress</a></li>
|
||||||
<li><a href="contact.html">Contact</a></li>
|
<li><a href="contact.html">Contact</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
<li><a href="exercises.html">Exercises</a></li>
|
<li><a href="exercises.html">Exercises</a></li>
|
||||||
<li><a href="tests.html">Tests</a></li>
|
<li><a href="tests.html">Tests</a></li>
|
||||||
<li><a href="reading.html">Reading</a></li>
|
<li><a href="reading.html">Reading</a></li>
|
||||||
|
<li><a href="progress.html">Progress</a></li>
|
||||||
<li><a href="contact.html">Contact</a></li>
|
<li><a href="contact.html">Contact</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
<li><a href="exercises.html">Exercises</a></li>
|
<li><a href="exercises.html">Exercises</a></li>
|
||||||
<li><a href="tests.html">Tests</a></li>
|
<li><a href="tests.html">Tests</a></li>
|
||||||
<li><a href="reading.html">Reading</a></li>
|
<li><a href="reading.html">Reading</a></li>
|
||||||
|
<li><a href="progress.html">Progress</a></li>
|
||||||
<li><a href="contact.html">Contact</a></li>
|
<li><a href="contact.html">Contact</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
@ -132,7 +133,7 @@
|
|||||||
|
|
||||||
<div class="result-box" id="test-result">
|
<div class="result-box" id="test-result">
|
||||||
<div class="score" id="score">0/10</div>
|
<div class="score" id="score">0/10</div>
|
||||||
<p>Keep learning and try again!</p>
|
<p id="test-detail">Keep learning and try again!</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
<li><a href="exercises.html">Exercises</a></li>
|
<li><a href="exercises.html">Exercises</a></li>
|
||||||
<li><a href="tests.html">Tests</a></li>
|
<li><a href="tests.html">Tests</a></li>
|
||||||
<li><a href="reading.html">Reading</a></li>
|
<li><a href="reading.html">Reading</a></li>
|
||||||
|
<li><a href="progress.html">Progress</a></li>
|
||||||
<li><a href="contact.html">Contact</a></li>
|
<li><a href="contact.html">Contact</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user