first commit
This commit is contained in:
643
app.js
Normal file
643
app.js
Normal file
@@ -0,0 +1,643 @@
|
|||||||
|
// EduCat: AI Study Buddy - Main Application Logic
|
||||||
|
|
||||||
|
class EduCatApp {
|
||||||
|
constructor() {
|
||||||
|
this.uploadedFiles = [];
|
||||||
|
this.studySessions = 0;
|
||||||
|
this.quizzesCompleted = 0;
|
||||||
|
this.generatedContent = [];
|
||||||
|
this.currentTab = 'dashboard';
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.setupEventListeners();
|
||||||
|
this.updateStats();
|
||||||
|
this.updateFileSelects();
|
||||||
|
this.showTab('dashboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
setupEventListeners() {
|
||||||
|
// Tab navigation
|
||||||
|
document.querySelectorAll('.nav__item').forEach(button => {
|
||||||
|
button.addEventListener('click', (e) => {
|
||||||
|
const tab = e.target.dataset.tab || 'dashboard';
|
||||||
|
this.showTab(tab);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// File upload - Fixed implementation
|
||||||
|
const uploadArea = document.getElementById('upload-area');
|
||||||
|
const fileInput = document.getElementById('file-input');
|
||||||
|
|
||||||
|
if (uploadArea && fileInput) {
|
||||||
|
uploadArea.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
fileInput.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
uploadArea.addEventListener('dragover', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
uploadArea.classList.add('drag-over');
|
||||||
|
});
|
||||||
|
|
||||||
|
uploadArea.addEventListener('dragleave', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
uploadArea.classList.remove('drag-over');
|
||||||
|
});
|
||||||
|
|
||||||
|
uploadArea.addEventListener('drop', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
uploadArea.classList.remove('drag-over');
|
||||||
|
const files = Array.from(e.dataTransfer.files);
|
||||||
|
this.processFiles(files);
|
||||||
|
});
|
||||||
|
|
||||||
|
fileInput.addEventListener('change', (e) => {
|
||||||
|
const files = Array.from(e.target.files);
|
||||||
|
this.processFiles(files);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// AI feature buttons
|
||||||
|
document.querySelectorAll('.feature-card').forEach(card => {
|
||||||
|
const button = card.querySelector('.btn');
|
||||||
|
if (button) {
|
||||||
|
button.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const feature = card.dataset.feature;
|
||||||
|
this.generateContent(feature);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Quiz generation
|
||||||
|
const generateQuizBtn = document.getElementById('generate-quiz');
|
||||||
|
if (generateQuizBtn) {
|
||||||
|
generateQuizBtn.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.generateQuiz();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Study planner interactions - Fixed implementation
|
||||||
|
this.setupPlannerEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
showTab(tabName) {
|
||||||
|
// Update navigation
|
||||||
|
document.querySelectorAll('.nav__item').forEach(item => {
|
||||||
|
item.classList.remove('active');
|
||||||
|
if (item.dataset.tab === tabName || (tabName === 'dashboard' && !item.dataset.tab)) {
|
||||||
|
item.classList.add('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update content
|
||||||
|
document.querySelectorAll('.tab-content').forEach(content => {
|
||||||
|
content.classList.remove('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
const targetTab = tabName === 'dashboard' ? 'dashboard' : tabName;
|
||||||
|
const targetContent = document.getElementById(targetTab);
|
||||||
|
if (targetContent) {
|
||||||
|
targetContent.classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentTab = tabName;
|
||||||
|
|
||||||
|
// Special handling for library tab
|
||||||
|
if (tabName === 'library') {
|
||||||
|
this.updateLibraryContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processFiles(files) {
|
||||||
|
if (!files || files.length === 0) {
|
||||||
|
alert('No files selected.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validFiles = files.filter(file => this.isValidFile(file));
|
||||||
|
|
||||||
|
if (validFiles.length === 0) {
|
||||||
|
alert('Please select valid file types: PDF, DOCX, PPTX, TXT, or XLSX');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validFiles.length !== files.length) {
|
||||||
|
alert('Some files were skipped due to invalid file types.');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.uploadFiles(validFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidFile(file) {
|
||||||
|
const validExtensions = ['pdf', 'docx', 'pptx', 'txt', 'xlsx'];
|
||||||
|
const fileName = file.name.toLowerCase();
|
||||||
|
return validExtensions.some(ext => fileName.endsWith('.' + ext));
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadFiles(files) {
|
||||||
|
const progressBar = document.getElementById('upload-progress');
|
||||||
|
const progressFill = document.getElementById('progress-fill');
|
||||||
|
const progressText = document.getElementById('progress-text');
|
||||||
|
|
||||||
|
if (progressBar) {
|
||||||
|
progressBar.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
let progress = 0;
|
||||||
|
const progressInterval = setInterval(() => {
|
||||||
|
progress += Math.random() * 20 + 5;
|
||||||
|
|
||||||
|
if (progressFill) {
|
||||||
|
progressFill.style.width = `${Math.min(progress, 100)}%`;
|
||||||
|
}
|
||||||
|
if (progressText) {
|
||||||
|
progressText.textContent = `Uploading... ${Math.round(Math.min(progress, 100))}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress >= 100) {
|
||||||
|
clearInterval(progressInterval);
|
||||||
|
this.completeUpload(files);
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
completeUpload(files) {
|
||||||
|
setTimeout(() => {
|
||||||
|
files.forEach(file => {
|
||||||
|
const fileData = {
|
||||||
|
id: Date.now() + Math.random(),
|
||||||
|
name: file.name,
|
||||||
|
size: this.formatFileSize(file.size || 50000), // Default size for demo
|
||||||
|
type: this.getFileType(file.name),
|
||||||
|
uploadDate: new Date().toLocaleDateString(),
|
||||||
|
content: this.generateMockContent(file.name)
|
||||||
|
};
|
||||||
|
this.uploadedFiles.push(fileData);
|
||||||
|
});
|
||||||
|
|
||||||
|
const progressBar = document.getElementById('upload-progress');
|
||||||
|
if (progressBar) {
|
||||||
|
progressBar.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateFileDisplay();
|
||||||
|
this.updateStats();
|
||||||
|
this.updateFileSelects();
|
||||||
|
this.addActivity(`Uploaded ${files.length} file(s)`);
|
||||||
|
|
||||||
|
// Show success message
|
||||||
|
alert(`Successfully uploaded ${files.length} file(s)!`);
|
||||||
|
|
||||||
|
// Clear file input
|
||||||
|
const fileInput = document.getElementById('file-input');
|
||||||
|
if (fileInput) {
|
||||||
|
fileInput.value = '';
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFileType(filename) {
|
||||||
|
const extension = filename.split('.').pop().toUpperCase();
|
||||||
|
return extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatFileSize(bytes) {
|
||||||
|
if (bytes === 0) return '0 Bytes';
|
||||||
|
const k = 1024;
|
||||||
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
generateMockContent(filename) {
|
||||||
|
const topics = ['Mathematics', 'Science', 'History', 'Literature', 'Computer Science'];
|
||||||
|
const randomTopic = topics[Math.floor(Math.random() * topics.length)];
|
||||||
|
return {
|
||||||
|
topic: randomTopic,
|
||||||
|
keyPoints: [
|
||||||
|
`Key concept from ${filename}`,
|
||||||
|
`Important theorem or principle`,
|
||||||
|
`Practical application example`,
|
||||||
|
`Historical context or background`
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFileDisplay() {
|
||||||
|
const container = document.getElementById('files-container');
|
||||||
|
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
if (this.uploadedFiles.length === 0) {
|
||||||
|
container.innerHTML = '<div class="empty-state"><p>No files uploaded yet. Upload your first file to get started!</p></div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
container.innerHTML = this.uploadedFiles.map(file => `
|
||||||
|
<div class="file-item" data-file-id="${file.id}">
|
||||||
|
<div class="file-icon">${file.type}</div>
|
||||||
|
<div class="file-info">
|
||||||
|
<div class="file-name">${file.name}</div>
|
||||||
|
<div class="file-meta">${file.size} • ${file.uploadDate}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStats() {
|
||||||
|
const filesCount = document.getElementById('files-count');
|
||||||
|
const sessionsCount = document.getElementById('sessions-count');
|
||||||
|
const quizzesCount = document.getElementById('quizzes-count');
|
||||||
|
|
||||||
|
if (filesCount) filesCount.textContent = this.uploadedFiles.length;
|
||||||
|
if (sessionsCount) sessionsCount.textContent = this.studySessions;
|
||||||
|
if (quizzesCount) quizzesCount.textContent = this.quizzesCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFileSelects() {
|
||||||
|
const select = document.getElementById('quiz-file-select');
|
||||||
|
if (!select) return;
|
||||||
|
|
||||||
|
select.innerHTML = '<option value="">Select a file to create quiz from</option>';
|
||||||
|
|
||||||
|
this.uploadedFiles.forEach(file => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = file.id;
|
||||||
|
option.textContent = file.name;
|
||||||
|
select.appendChild(option);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addActivity(activity) {
|
||||||
|
const activityList = document.getElementById('activity-list');
|
||||||
|
if (!activityList) return;
|
||||||
|
|
||||||
|
const timestamp = new Date().toLocaleTimeString();
|
||||||
|
|
||||||
|
// Remove empty state if it exists
|
||||||
|
const emptyState = activityList.querySelector('.empty-state');
|
||||||
|
if (emptyState) {
|
||||||
|
emptyState.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
const activityItem = document.createElement('div');
|
||||||
|
activityItem.className = 'activity-item';
|
||||||
|
activityItem.innerHTML = `
|
||||||
|
<span>📝</span>
|
||||||
|
<span>${activity}</span>
|
||||||
|
<small>${timestamp}</small>
|
||||||
|
`;
|
||||||
|
|
||||||
|
activityList.insertBefore(activityItem, activityList.firstChild);
|
||||||
|
|
||||||
|
// Keep only last 5 activities
|
||||||
|
const items = activityList.querySelectorAll('.activity-item');
|
||||||
|
if (items.length > 5) {
|
||||||
|
items[items.length - 1].remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generateContent(feature) {
|
||||||
|
if (this.uploadedFiles.length === 0) {
|
||||||
|
alert('Please upload some files first before generating content.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showLoadingModal(`Generating ${feature.replace('-', ' ')}...`);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const content = this.createMockContent(feature);
|
||||||
|
this.generatedContent.push(content);
|
||||||
|
this.hideLoadingModal();
|
||||||
|
this.updateLibraryContent();
|
||||||
|
this.addActivity(`Generated ${feature.replace('-', ' ')}`);
|
||||||
|
|
||||||
|
// Switch to library tab to show the generated content
|
||||||
|
this.showTab('library');
|
||||||
|
}, 2000 + Math.random() * 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
createMockContent(feature) {
|
||||||
|
const randomFile = this.uploadedFiles[Math.floor(Math.random() * this.uploadedFiles.length)];
|
||||||
|
const timestamp = new Date().toLocaleString();
|
||||||
|
|
||||||
|
const contentMap = {
|
||||||
|
'study-guide': {
|
||||||
|
title: `Study Guide: ${randomFile.content.topic}`,
|
||||||
|
type: 'Study Guide',
|
||||||
|
content: `
|
||||||
|
<h4>Chapter Overview</h4>
|
||||||
|
<p>This study guide covers the key concepts from ${randomFile.name}.</p>
|
||||||
|
|
||||||
|
<h4>Key Topics</h4>
|
||||||
|
<ul>
|
||||||
|
${randomFile.content.keyPoints.map(point => `<li>${point}</li>`).join('')}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4>Study Tips</h4>
|
||||||
|
<ul>
|
||||||
|
<li>Review each section multiple times</li>
|
||||||
|
<li>Create flashcards for key terms</li>
|
||||||
|
<li>Practice with sample problems</li>
|
||||||
|
<li>Form study groups for discussion</li>
|
||||||
|
</ul>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
'quiz': {
|
||||||
|
title: `Practice Quiz: ${randomFile.content.topic}`,
|
||||||
|
type: 'Quiz',
|
||||||
|
content: `
|
||||||
|
<div class="quiz-questions">
|
||||||
|
<div class="quiz-question">
|
||||||
|
<div class="question-text">1. What is the main concept discussed in the uploaded material?</div>
|
||||||
|
<div class="quiz-options-list">
|
||||||
|
<label class="quiz-option">
|
||||||
|
<input type="radio" name="q1" value="a">
|
||||||
|
<span>${randomFile.content.keyPoints[0]}</span>
|
||||||
|
</label>
|
||||||
|
<label class="quiz-option">
|
||||||
|
<input type="radio" name="q1" value="b">
|
||||||
|
<span>Alternative concept</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
'summary': {
|
||||||
|
title: `Summary: ${randomFile.content.topic}`,
|
||||||
|
type: 'Summary',
|
||||||
|
content: `
|
||||||
|
<p><strong>Document:</strong> ${randomFile.name}</p>
|
||||||
|
<p><strong>Topic:</strong> ${randomFile.content.topic}</p>
|
||||||
|
|
||||||
|
<h4>Key Points Summary</h4>
|
||||||
|
<p>The main concepts covered include:</p>
|
||||||
|
<ul>
|
||||||
|
${randomFile.content.keyPoints.map(point => `<li>${point}</li>`).join('')}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>This material provides a comprehensive overview of ${randomFile.content.topic} with practical applications and theoretical foundations.</p>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
'flashcards': {
|
||||||
|
title: `Flashcards: ${randomFile.content.topic}`,
|
||||||
|
type: 'Flashcards',
|
||||||
|
content: `
|
||||||
|
<div class="flashcard-set">
|
||||||
|
${randomFile.content.keyPoints.map((point, index) => `
|
||||||
|
<div class="flashcard" style="margin-bottom: 16px; padding: 16px; border: 1px solid var(--color-border); border-radius: 8px;">
|
||||||
|
<div class="flashcard-front"><strong>Card ${index + 1}:</strong> What is ${point.toLowerCase()}?</div>
|
||||||
|
<div class="flashcard-back" style="margin-top: 8px; color: var(--color-text-secondary);">Answer: ${point}</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: Date.now() + Math.random(),
|
||||||
|
...contentMap[feature],
|
||||||
|
sourceFile: randomFile.name,
|
||||||
|
createdAt: timestamp
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLibraryContent() {
|
||||||
|
const container = document.getElementById('generated-content');
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
if (this.generatedContent.length === 0) {
|
||||||
|
container.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
container.style.display = 'block';
|
||||||
|
container.innerHTML = `
|
||||||
|
<h3>Generated Study Materials</h3>
|
||||||
|
${this.generatedContent.map(content => `
|
||||||
|
<div class="content-item">
|
||||||
|
<div class="content-header">
|
||||||
|
<span class="content-title">${content.title}</span>
|
||||||
|
<span class="status status--success">${content.type}</span>
|
||||||
|
</div>
|
||||||
|
<div class="content-body">
|
||||||
|
<p><small>Generated from: ${content.sourceFile} • ${content.createdAt}</small></p>
|
||||||
|
${content.content}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateQuiz() {
|
||||||
|
const fileSelect = document.getElementById('quiz-file-select');
|
||||||
|
const questionsSelect = document.getElementById('quiz-questions');
|
||||||
|
|
||||||
|
if (!fileSelect || !fileSelect.value) {
|
||||||
|
alert('Please select a file to generate quiz from.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedFile = this.uploadedFiles.find(file => file.id == fileSelect.value);
|
||||||
|
const numQuestions = parseInt(questionsSelect.value) || 10;
|
||||||
|
|
||||||
|
this.showLoadingModal('Generating quiz questions...');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const quiz = this.createQuizQuestions(selectedFile, numQuestions);
|
||||||
|
this.displayQuiz(quiz);
|
||||||
|
this.hideLoadingModal();
|
||||||
|
this.addActivity(`Generated ${numQuestions}-question quiz`);
|
||||||
|
}, 1500 + Math.random() * 1500);
|
||||||
|
}
|
||||||
|
|
||||||
|
createQuizQuestions(file, numQuestions) {
|
||||||
|
const questions = [];
|
||||||
|
const questionTypes = [
|
||||||
|
'What is the main concept of',
|
||||||
|
'Which of the following best describes',
|
||||||
|
'What is the key principle behind',
|
||||||
|
'How does this concept apply to',
|
||||||
|
'What is the relationship between'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let i = 0; i < numQuestions; i++) {
|
||||||
|
const questionType = questionTypes[Math.floor(Math.random() * questionTypes.length)];
|
||||||
|
const keyPoint = file.content.keyPoints[i % file.content.keyPoints.length];
|
||||||
|
|
||||||
|
questions.push({
|
||||||
|
id: i + 1,
|
||||||
|
question: `${questionType} ${keyPoint.toLowerCase()}?`,
|
||||||
|
options: [
|
||||||
|
keyPoint,
|
||||||
|
'Alternative option A',
|
||||||
|
'Alternative option B',
|
||||||
|
'Alternative option C'
|
||||||
|
].sort(() => Math.random() - 0.5),
|
||||||
|
correct: keyPoint
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: `Quiz: ${file.content.topic}`,
|
||||||
|
source: file.name,
|
||||||
|
questions: questions
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
displayQuiz(quiz) {
|
||||||
|
const container = document.getElementById('quiz-container');
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
container.classList.remove('hidden');
|
||||||
|
|
||||||
|
container.innerHTML = `
|
||||||
|
<div class="quiz-header">
|
||||||
|
<h3>${quiz.title}</h3>
|
||||||
|
<p>Source: ${quiz.source}</p>
|
||||||
|
</div>
|
||||||
|
<div class="quiz-questions">
|
||||||
|
${quiz.questions.map(q => `
|
||||||
|
<div class="quiz-question">
|
||||||
|
<div class="question-text">${q.id}. ${q.question}</div>
|
||||||
|
<div class="quiz-options-list">
|
||||||
|
${q.options.map((option, index) => `
|
||||||
|
<label class="quiz-option">
|
||||||
|
<input type="radio" name="q${q.id}" value="${option}">
|
||||||
|
<span>${option}</span>
|
||||||
|
</label>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
<button class="btn btn--primary" onclick="app.submitQuiz()">Submit Quiz</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
submitQuiz() {
|
||||||
|
const questions = document.querySelectorAll('.quiz-question');
|
||||||
|
let score = 0;
|
||||||
|
let total = questions.length;
|
||||||
|
|
||||||
|
questions.forEach((question, index) => {
|
||||||
|
const selected = question.querySelector('input[type="radio"]:checked');
|
||||||
|
if (selected) {
|
||||||
|
// For demo purposes, we'll give a random score
|
||||||
|
if (Math.random() > 0.3) score++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.quizzesCompleted++;
|
||||||
|
this.updateStats();
|
||||||
|
this.addActivity(`Completed quiz - Score: ${score}/${total}`);
|
||||||
|
|
||||||
|
alert(`Quiz completed! Your score: ${score}/${total} (${Math.round((score/total) * 100)}%)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupPlannerEvents() {
|
||||||
|
// Wait for DOM to be ready and then attach events
|
||||||
|
setTimeout(() => {
|
||||||
|
const plannerButtons = document.querySelectorAll('.planner-card .btn--secondary');
|
||||||
|
plannerButtons.forEach((btn, index) => {
|
||||||
|
// Remove existing listeners to prevent duplication
|
||||||
|
btn.replaceWith(btn.cloneNode(true));
|
||||||
|
const newBtn = document.querySelectorAll('.planner-card .btn--secondary')[index];
|
||||||
|
|
||||||
|
newBtn.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
if (index === 0) {
|
||||||
|
this.addStudySession();
|
||||||
|
} else if (index === 1) {
|
||||||
|
this.addStudyGoal();
|
||||||
|
} else if (index === 2) {
|
||||||
|
this.setReminder();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Goal checkboxes
|
||||||
|
const goalCheckboxes = document.querySelectorAll('.goal-item input[type="checkbox"]');
|
||||||
|
goalCheckboxes.forEach(checkbox => {
|
||||||
|
checkbox.addEventListener('change', () => {
|
||||||
|
if (checkbox.checked) {
|
||||||
|
this.studySessions++;
|
||||||
|
this.updateStats();
|
||||||
|
this.addActivity('Completed study goal');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
addStudySession() {
|
||||||
|
const time = prompt('Enter study time (e.g., 3:00 PM):');
|
||||||
|
const subject = prompt('Enter subject:');
|
||||||
|
|
||||||
|
if (time && subject) {
|
||||||
|
this.studySessions++;
|
||||||
|
this.updateStats();
|
||||||
|
this.addActivity(`Scheduled: ${subject} at ${time}`);
|
||||||
|
alert('Study session added to your schedule!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addStudyGoal() {
|
||||||
|
const goal = prompt('Enter your study goal:');
|
||||||
|
if (goal) {
|
||||||
|
this.addActivity(`New goal: ${goal}`);
|
||||||
|
alert('Study goal added!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setReminder() {
|
||||||
|
const reminder = prompt('Enter reminder text:');
|
||||||
|
if (reminder) {
|
||||||
|
this.addActivity(`Set reminder: ${reminder}`);
|
||||||
|
alert('Reminder set!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showLoadingModal(title, text = 'Please wait while we analyze your content and generate study materials.') {
|
||||||
|
const modal = document.getElementById('loading-modal');
|
||||||
|
const titleEl = document.getElementById('loading-title');
|
||||||
|
const textEl = document.getElementById('loading-text');
|
||||||
|
|
||||||
|
if (modal) modal.classList.remove('hidden');
|
||||||
|
if (titleEl) titleEl.textContent = title;
|
||||||
|
if (textEl) textEl.textContent = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
hideLoadingModal() {
|
||||||
|
const modal = document.getElementById('loading-modal');
|
||||||
|
if (modal) modal.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the application
|
||||||
|
let app;
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
app = new EduCatApp();
|
||||||
|
|
||||||
|
// Add some sample activity for demo
|
||||||
|
setTimeout(() => {
|
||||||
|
app.addActivity('Welcome to EduCat!');
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle modal click to close
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
if (e.target.id === 'loading-modal') {
|
||||||
|
if (app) app.hideLoadingModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
247
index.html
Normal file
247
index.html
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>EduCat: AI Study Buddy</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="header">
|
||||||
|
<div class="container">
|
||||||
|
<div class="header__content">
|
||||||
|
<div class="logo">
|
||||||
|
<h1 class="logo__text">🐱 EduCat</h1>
|
||||||
|
<span class="logo__subtitle">AI Study Buddy</span>
|
||||||
|
</div>
|
||||||
|
<nav class="nav">
|
||||||
|
<button class="nav__item" data-tab="upload">Upload Files</button>
|
||||||
|
<button class="nav__item" data-tab="library">My Notes</button>
|
||||||
|
<button class="nav__item" data-tab="quiz">Quiz Generator</button>
|
||||||
|
<button class="nav__item" data-tab="planner">Study Planner</button>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div class="welcome-message">
|
||||||
|
<p>Welcome to EduCat - Your AI Study Buddy!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="main">
|
||||||
|
<div class="container">
|
||||||
|
<!-- Dashboard Tab -->
|
||||||
|
<section id="dashboard" class="tab-content active">
|
||||||
|
<div class="hero">
|
||||||
|
<h2>Transform Your Study Materials with AI</h2>
|
||||||
|
<p>Upload your notes, textbooks, and study materials. Let our AI create personalized study guides, quizzes, summaries, and flashcards to boost your learning efficiency.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stats-grid">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-card__icon">📁</div>
|
||||||
|
<div class="stat-card__content">
|
||||||
|
<span class="stat-card__number" id="files-count">0</span>
|
||||||
|
<span class="stat-card__label">Files Uploaded</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-card__icon">📚</div>
|
||||||
|
<div class="stat-card__content">
|
||||||
|
<span class="stat-card__number" id="sessions-count">0</span>
|
||||||
|
<span class="stat-card__label">Study Sessions</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-card__icon">🧠</div>
|
||||||
|
<div class="stat-card__content">
|
||||||
|
<span class="stat-card__number" id="quizzes-count">0</span>
|
||||||
|
<span class="stat-card__label">Quizzes Completed</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="recent-activity">
|
||||||
|
<h3>Recent Activity</h3>
|
||||||
|
<div id="activity-list" class="activity-list">
|
||||||
|
<div class="activity-item empty-state">
|
||||||
|
<p>No recent activity. Start by uploading your first file!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Upload Tab -->
|
||||||
|
<section id="upload" class="tab-content">
|
||||||
|
<div class="upload-section">
|
||||||
|
<h2>Upload Your Study Materials</h2>
|
||||||
|
<div class="upload-area" id="upload-area">
|
||||||
|
<div class="upload-area__content">
|
||||||
|
<div class="upload-area__icon">📤</div>
|
||||||
|
<h3>Drag & Drop Files Here</h3>
|
||||||
|
<p>or click to browse files</p>
|
||||||
|
<input type="file" id="file-input" multiple accept=".pdf,.docx,.pptx,.txt,.xlsx">
|
||||||
|
</div>
|
||||||
|
<div class="upload-area__formats">
|
||||||
|
<span class="format-badge">PDF</span>
|
||||||
|
<span class="format-badge">DOCX</span>
|
||||||
|
<span class="format-badge">PPTX</span>
|
||||||
|
<span class="format-badge">TXT</span>
|
||||||
|
<span class="format-badge">XLSX</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="upload-progress" class="upload-progress hidden">
|
||||||
|
<div class="progress-bar">
|
||||||
|
<div class="progress-fill" id="progress-fill"></div>
|
||||||
|
</div>
|
||||||
|
<span id="progress-text">Uploading...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="file-list" class="file-list">
|
||||||
|
<h3>Uploaded Files</h3>
|
||||||
|
<div id="files-container" class="files-container">
|
||||||
|
<div class="empty-state">
|
||||||
|
<p>No files uploaded yet. Upload your first file to get started!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Library Tab -->
|
||||||
|
<section id="library" class="tab-content">
|
||||||
|
<div class="library-section">
|
||||||
|
<h2>My Study Library</h2>
|
||||||
|
<div class="ai-features">
|
||||||
|
<div class="feature-card" data-feature="study-guide">
|
||||||
|
<div class="feature-card__icon">📖</div>
|
||||||
|
<h3>Study Guide Generator</h3>
|
||||||
|
<p>Convert your files into structured study guides</p>
|
||||||
|
<button class="btn btn--primary">Generate Study Guide</button>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card" data-feature="quiz">
|
||||||
|
<div class="feature-card__icon">❓</div>
|
||||||
|
<h3>Quiz Creator</h3>
|
||||||
|
<p>Generate practice questions from your content</p>
|
||||||
|
<button class="btn btn--primary">Create Quiz</button>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card" data-feature="summary">
|
||||||
|
<div class="feature-card__icon">📝</div>
|
||||||
|
<h3>Summary Generator</h3>
|
||||||
|
<p>Create concise summaries of long documents</p>
|
||||||
|
<button class="btn btn--primary">Generate Summary</button>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card" data-feature="flashcards">
|
||||||
|
<div class="feature-card__icon">🃏</div>
|
||||||
|
<h3>Flashcard Maker</h3>
|
||||||
|
<p>Extract key concepts into flashcards</p>
|
||||||
|
<button class="btn btn--primary">Create Flashcards</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="generated-content" class="generated-content">
|
||||||
|
<!-- Generated content will appear here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Quiz Tab -->
|
||||||
|
<section id="quiz" class="tab-content">
|
||||||
|
<div class="quiz-section">
|
||||||
|
<h2>Quiz Generator</h2>
|
||||||
|
<div class="quiz-options">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Select Study Material</label>
|
||||||
|
<select id="quiz-file-select" class="form-control">
|
||||||
|
<option value="">Select a file to create quiz from</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">Number of Questions</label>
|
||||||
|
<select class="form-control" id="quiz-questions">
|
||||||
|
<option value="5">5 Questions</option>
|
||||||
|
<option value="10" selected>10 Questions</option>
|
||||||
|
<option value="15">15 Questions</option>
|
||||||
|
<option value="20">20 Questions</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn--primary" id="generate-quiz">Generate Quiz</button>
|
||||||
|
</div>
|
||||||
|
<div id="quiz-container" class="quiz-container hidden">
|
||||||
|
<!-- Quiz questions will be generated here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Planner Tab -->
|
||||||
|
<section id="planner" class="tab-content">
|
||||||
|
<div class="planner-section">
|
||||||
|
<h2>Study Planner</h2>
|
||||||
|
<div class="planner-grid">
|
||||||
|
<div class="planner-card">
|
||||||
|
<h3>📅 Study Schedule</h3>
|
||||||
|
<div class="study-schedule">
|
||||||
|
<div class="schedule-item">
|
||||||
|
<span class="schedule-time">9:00 AM</span>
|
||||||
|
<span class="schedule-subject">Mathematics Review</span>
|
||||||
|
</div>
|
||||||
|
<div class="schedule-item">
|
||||||
|
<span class="schedule-time">2:00 PM</span>
|
||||||
|
<span class="schedule-subject">Science Quiz Practice</span>
|
||||||
|
</div>
|
||||||
|
<div class="schedule-item">
|
||||||
|
<span class="schedule-time">7:00 PM</span>
|
||||||
|
<span class="schedule-subject">History Flashcards</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn--secondary">Add Study Session</button>
|
||||||
|
</div>
|
||||||
|
<div class="planner-card">
|
||||||
|
<h3>🎯 Study Goals</h3>
|
||||||
|
<div class="goals-list">
|
||||||
|
<div class="goal-item">
|
||||||
|
<input type="checkbox" id="goal1">
|
||||||
|
<label for="goal1">Complete Math Chapter 5</label>
|
||||||
|
</div>
|
||||||
|
<div class="goal-item">
|
||||||
|
<input type="checkbox" id="goal2">
|
||||||
|
<label for="goal2">Review Science Notes</label>
|
||||||
|
</div>
|
||||||
|
<div class="goal-item">
|
||||||
|
<input type="checkbox" id="goal3">
|
||||||
|
<label for="goal3">Practice 20 Quiz Questions</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn--secondary">Add Goal</button>
|
||||||
|
</div>
|
||||||
|
<div class="planner-card">
|
||||||
|
<h3>⏰ Reminders</h3>
|
||||||
|
<div class="reminders-list">
|
||||||
|
<div class="reminder-item">
|
||||||
|
<span class="reminder-text">Math exam in 3 days</span>
|
||||||
|
<span class="status status--warning">Pending</span>
|
||||||
|
</div>
|
||||||
|
<div class="reminder-item">
|
||||||
|
<span class="reminder-text">Submit assignment</span>
|
||||||
|
<span class="status status--error">Overdue</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn--secondary">Set Reminder</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- Loading Modal -->
|
||||||
|
<div id="loading-modal" class="modal hidden">
|
||||||
|
<div class="modal__content">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
<h3 id="loading-title">Processing with AI...</h3>
|
||||||
|
<p id="loading-text">Please wait while we analyze your content and generate study materials.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user