Update 13 files
- /TeacherDashboard/index.html - /TeacherDashboard/TeacherDashboard.code-workspace - /TeacherDashboard/components/resourceModal.html - /TeacherDashboard/components/subjectModal.html - /TeacherDashboard/components/topicModal.html - /TeacherDashboard/js/main.js - /TeacherDashboard/js/subjects/colors.js - /TeacherDashboard/js/subjects/subjectManager.js - /TeacherDashboard/js/subjects/SubjectModel.js - /TeacherDashboard/js/subjects/SubjectStorage.js - /TeacherDashboard/js/topics/TopicModel.js - /TeacherDashboard/js/topics/topicManager.js - /TeacherDashboard/styles/main.css
This commit is contained in:
committed by
Matthias Grief
parent
71b673fa9f
commit
5096106835
47
TeacherDashboard/js/subjects/SubjectModel.js
Normal file
47
TeacherDashboard/js/subjects/SubjectModel.js
Normal file
@@ -0,0 +1,47 @@
|
||||
export class SubjectModel {
|
||||
constructor(data) {
|
||||
this.id = data.id || crypto.randomUUID();
|
||||
this.name = data.name;
|
||||
this.description = data.description || '';
|
||||
this.color = data.color;
|
||||
this.icon = data.icon;
|
||||
this.createdAt = data.createdAt || new Date().toISOString();
|
||||
this.updatedAt = new Date().toISOString();
|
||||
this.topics = data.topics || [];
|
||||
this.resources = data.resources || [];
|
||||
this.metadata = {
|
||||
lastAccessed: new Date().toISOString(),
|
||||
topicCount: 0,
|
||||
resourceCount: 0
|
||||
};
|
||||
this.content = data.content || '';
|
||||
this.materials = data.materials || [];
|
||||
}
|
||||
|
||||
validate() {
|
||||
const required = ['name', 'color', 'icon'];
|
||||
const missing = required.filter(field => !this[field]);
|
||||
|
||||
if (missing.length > 0) {
|
||||
throw new Error(`Missing required fields: ${missing.join(', ')}`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
color: this.color,
|
||||
icon: this.icon,
|
||||
createdAt: this.createdAt,
|
||||
updatedAt: this.updatedAt,
|
||||
topics: this.topics,
|
||||
resources: this.resources,
|
||||
metadata: this.metadata,
|
||||
content: this.content,
|
||||
materials: this.materials
|
||||
};
|
||||
}
|
||||
}
|
||||
39
TeacherDashboard/js/subjects/SubjectStorage.js
Normal file
39
TeacherDashboard/js/subjects/SubjectStorage.js
Normal file
@@ -0,0 +1,39 @@
|
||||
export class SubjectStorage {
|
||||
constructor() {
|
||||
this.storageKey = 'teacherDash_subjects';
|
||||
}
|
||||
|
||||
async getAllSubjects() {
|
||||
try {
|
||||
const data = localStorage.getItem(this.storageKey);
|
||||
return data ? JSON.parse(data) : [];
|
||||
} catch (error) {
|
||||
console.error('Error loading subjects:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async saveSubject(subject) {
|
||||
try {
|
||||
const subjects = await this.getAllSubjects();
|
||||
const existingIndex = subjects.findIndex(s => s.id === subject.id);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
subjects[existingIndex] = subject;
|
||||
} else {
|
||||
subjects.push(subject);
|
||||
}
|
||||
|
||||
localStorage.setItem(this.storageKey, JSON.stringify(subjects));
|
||||
return subject;
|
||||
} catch (error) {
|
||||
throw new Error('Failed to save subject: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async deleteSubject(subjectId) {
|
||||
const subjects = await this.getAllSubjects();
|
||||
const filtered = subjects.filter(s => s.id !== subjectId);
|
||||
localStorage.setItem(this.storageKey, JSON.stringify(filtered));
|
||||
}
|
||||
}
|
||||
21
TeacherDashboard/js/subjects/colors.js
Normal file
21
TeacherDashboard/js/subjects/colors.js
Normal file
@@ -0,0 +1,21 @@
|
||||
export const subjectColors = {
|
||||
red: { hex: '#FF6B6B', name: 'Rot' },
|
||||
teal: { hex: '#4ECDC4', name: 'Türkis' },
|
||||
blue: { hex: '#45B7D1', name: 'Blau' },
|
||||
green: { hex: '#96CEB4', name: 'Grün' },
|
||||
brown: { hex: '#D4A373', name: 'Braun' },
|
||||
purple: { hex: '#9B5DE5', name: 'Lila' },
|
||||
pink: { hex: '#F15BB5', name: 'Pink' },
|
||||
yellow: { hex: '#FEE440', name: 'Gelb' },
|
||||
lightBlue: { hex: '#00BBF9', name: 'Hellblau' },
|
||||
mint: { hex: '#00F5D4', name: 'Mint' }
|
||||
};
|
||||
|
||||
export function generateColorPalette() {
|
||||
return Object.entries(subjectColors)
|
||||
.map(([key, color]) => ({
|
||||
id: key,
|
||||
hex: color.hex,
|
||||
name: color.name
|
||||
}));
|
||||
}
|
||||
139
TeacherDashboard/js/subjects/subjectManager.js
Normal file
139
TeacherDashboard/js/subjects/subjectManager.js
Normal file
@@ -0,0 +1,139 @@
|
||||
import { generateColorPalette } from './colors.js';
|
||||
import { SubjectModel } from './SubjectModel.js';
|
||||
import { SubjectStorage } from './SubjectStorage.js';
|
||||
|
||||
export class SubjectManager {
|
||||
constructor() {
|
||||
this.storage = new SubjectStorage();
|
||||
this.subjects = [];
|
||||
this.initializeEventListeners();
|
||||
}
|
||||
|
||||
initializeEventListeners() {
|
||||
const form = document.getElementById('subjectForm');
|
||||
if (form) {
|
||||
form.addEventListener('submit', (e) => this.handleSubjectSubmit(e));
|
||||
}
|
||||
|
||||
this.initializeColorPicker();
|
||||
this.initializeIconPicker();
|
||||
}
|
||||
|
||||
initializeColorPicker() {
|
||||
const palette = generateColorPalette();
|
||||
const container = document.getElementById('colorPalette');
|
||||
|
||||
if (container) {
|
||||
container.innerHTML = palette.map(color => `
|
||||
<div class="color-option"
|
||||
style="background-color: ${color.hex}"
|
||||
data-color="${color.hex}"
|
||||
title="${color.name}">
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
this.addColorPickerListeners();
|
||||
}
|
||||
}
|
||||
|
||||
initializeIconPicker() {
|
||||
const iconOptions = document.querySelectorAll('.icon-option');
|
||||
iconOptions.forEach(option => {
|
||||
option.addEventListener('click', () => {
|
||||
iconOptions.forEach(opt => opt.classList.remove('selected'));
|
||||
option.classList.add('selected');
|
||||
document.getElementById('selectedIcon').value = option.dataset.icon;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addColorPickerListeners() {
|
||||
const colorOptions = document.querySelectorAll('.color-option');
|
||||
colorOptions.forEach(option => {
|
||||
option.addEventListener('click', () => {
|
||||
colorOptions.forEach(opt => opt.classList.remove('selected'));
|
||||
option.classList.add('selected');
|
||||
document.getElementById('selectedColor').value = option.dataset.color;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async handleSubjectSubmit(e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.target);
|
||||
|
||||
try {
|
||||
const subjectData = {
|
||||
name: formData.get('displayName'),
|
||||
description: formData.get('description'),
|
||||
color: formData.get('color'),
|
||||
icon: formData.get('icon'),
|
||||
materials: await this.processFiles(formData.getAll('materials[]'))
|
||||
};
|
||||
|
||||
const subject = new SubjectModel(subjectData);
|
||||
subject.validate();
|
||||
|
||||
await this.storage.saveSubject(subject.toJSON());
|
||||
this.updateSubjectsList(subject.toJSON());
|
||||
closeModal('subjectModal');
|
||||
e.target.reset();
|
||||
|
||||
return subject;
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to create subject: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async processFiles(files) {
|
||||
return Array.from(files).map(file => ({
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: file.type,
|
||||
lastModified: file.lastModified
|
||||
}));
|
||||
}
|
||||
|
||||
async loadSubjects() {
|
||||
const subjects = await this.storage.getAllSubjects();
|
||||
subjects.forEach(subject => this.updateSubjectsList(subject));
|
||||
}
|
||||
|
||||
validateSubjectForm(formData) {
|
||||
const requiredFields = ['displayName', 'color', 'icon'];
|
||||
return requiredFields.every(field => formData.get(field)?.trim());
|
||||
}
|
||||
|
||||
updateSubjectsList(subject) {
|
||||
const container = document.getElementById('subjectsList');
|
||||
if (!container) {
|
||||
const mainContent = document.querySelector('main');
|
||||
const subjectsSection = document.createElement('div');
|
||||
subjectsSection.className = 'mt-8';
|
||||
subjectsSection.innerHTML = `
|
||||
<h2 class="text-xl font-semibold mb-4">Meine Fächer</h2>
|
||||
<div id="subjectsList" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
</div>
|
||||
`;
|
||||
mainContent.appendChild(subjectsSection);
|
||||
}
|
||||
|
||||
const subjectElement = this.createSubjectElement(subject);
|
||||
document.getElementById('subjectsList').appendChild(subjectElement);
|
||||
}
|
||||
|
||||
createSubjectElement(subject) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'bg-white p-4 rounded-xl shadow-sm border border-gray-100 flex items-center gap-4';
|
||||
div.innerHTML = `
|
||||
<div class="w-10 h-10 rounded-lg flex items-center justify-center" style="background-color: ${subject.color}">
|
||||
<i class="fas ${subject.icon} text-white"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-medium">${subject.name}</h3>
|
||||
<p class="text-sm text-gray-500">${subject.description || ''}</p>
|
||||
</div>
|
||||
`;
|
||||
return div;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user