diff --git a/TeacherDashboard/TeacherDashboard.code-workspace b/TeacherDashboard/TeacherDashboard.code-workspace
new file mode 100644
index 0000000..876a149
--- /dev/null
+++ b/TeacherDashboard/TeacherDashboard.code-workspace
@@ -0,0 +1,8 @@
+{
+ "folders": [
+ {
+ "path": "."
+ }
+ ],
+ "settings": {}
+}
\ No newline at end of file
diff --git a/TeacherDashboard/components/resourceModal.html b/TeacherDashboard/components/resourceModal.html
new file mode 100644
index 0000000..7139630
--- /dev/null
+++ b/TeacherDashboard/components/resourceModal.html
@@ -0,0 +1,33 @@
+
+
+
+
+
Materialien hochladen
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TeacherDashboard/components/subjectModal.html b/TeacherDashboard/components/subjectModal.html
new file mode 100644
index 0000000..546d7b2
--- /dev/null
+++ b/TeacherDashboard/components/subjectModal.html
@@ -0,0 +1,67 @@
+
+
+
+
+
Neues Fach erstellen
+
+
+
+
+
+
+
diff --git a/TeacherDashboard/components/topicModal.html b/TeacherDashboard/components/topicModal.html
new file mode 100644
index 0000000..a9f248b
--- /dev/null
+++ b/TeacherDashboard/components/topicModal.html
@@ -0,0 +1,74 @@
+
+
+
+
+
Neues Thema erstellen
+
+
+
+
+
+
+
+
+
+ Themenname
+
+
+
+ Fach
+
+ Fach auswählen...
+
+
+
+ Kurzbeschreibung
+
+
+
+
+
+
+
+
+
Bildungsinhalt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Abbrechen
+
+
+ Speichern
+
+
+
+
+
diff --git a/TeacherDashboard/index.html b/TeacherDashboard/index.html
new file mode 100644
index 0000000..d564d06
--- /dev/null
+++ b/TeacherDashboard/index.html
@@ -0,0 +1,152 @@
+
+
+
+
+
+ Lehrer Dashboard
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dashboard
+
+
+
+
+
+
Fach erstellen
+
Erstellen Sie ein neues Fach für Ihren Unterricht.
+
+ Neues Fach
+
+
+
+
+
+
Thema hinzufügen
+
Fügen Sie ein neues Thema zu einem Fach hinzu.
+
+ Neues Thema
+
+
+
+
+
+
Materialien hochladen
+
Laden Sie Unterrichtsmaterialien hoch.
+
+ Materialien hochladen
+
+
+
+
+
+
+
Letzte Aktivitäten
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TeacherDashboard/js/main.js b/TeacherDashboard/js/main.js
new file mode 100644
index 0000000..ba52edc
--- /dev/null
+++ b/TeacherDashboard/js/main.js
@@ -0,0 +1,113 @@
+import { SubjectManager } from './subjects/subjectManager.js';
+import { TopicManager } from './topics/topicManager.js';
+
+// Make modal functions globally available
+window.openModal = (modalId) => {
+ const modal = document.getElementById(modalId);
+ modal.classList.remove('hidden');
+
+ if (modalId === 'topicModal') {
+ document.dispatchEvent(new Event('openTopicModal'));
+ }
+
+ gsap.fromTo(modal.children[0],
+ { y: -50, opacity: 0 },
+ { y: 0, opacity: 1, duration: 0.3 }
+ );
+};
+
+window.closeModal = (modalId) => {
+ const modal = document.getElementById(modalId);
+ gsap.to(modal.children[0], {
+ y: -50,
+ opacity: 0,
+ duration: 0.3,
+ onComplete: () => {
+ modal.classList.add('hidden');
+ }
+ });
+};
+
+// Make this function globally available
+window.openSubjectModal = () => {
+ openModal('subjectModal');
+};
+
+async function loadModals() {
+ const modalContainer = document.getElementById('modalContainer');
+ const modals = ['subjectModal', 'topicModal', 'resourceModal'];
+
+ for (const modal of modals) {
+ try {
+ const response = await fetch(`components/${modal}.html`);
+ const html = await response.text();
+ modalContainer.innerHTML += html;
+ } catch (error) {
+ console.error(`Error loading ${modal}:`, error);
+ }
+ }
+
+ // Initialize color picker functionality for subject modal
+ initializeColorPicker();
+}
+
+function initializeColorPicker() {
+ const colorOptions = document.querySelectorAll('.color-option');
+ colorOptions.forEach(option => {
+ option.addEventListener('click', function() {
+ document.querySelectorAll('.color-option').forEach(opt =>
+ opt.classList.remove('ring-2', 'ring-blue-500'));
+ this.classList.add('ring-2', 'ring-blue-500');
+ document.getElementById('selectedColor').value = this.dataset.color;
+ });
+ });
+}
+
+// Initialize everything after DOM content is loaded
+document.addEventListener('DOMContentLoaded', async () => {
+ await loadModals();
+ const subjectManager = new SubjectManager();
+ // Make topicManager globally available
+ window.topicManager = new TopicManager();
+
+ // Initialize event listeners for the subject form
+ const form = document.getElementById('subjectForm');
+ if (form) {
+ form.addEventListener('submit', async (e) => {
+ e.preventDefault();
+ const submitButton = form.querySelector('button[type="submit"]');
+ submitButton.disabled = true;
+ submitButton.innerHTML = ' Speichern...';
+
+ try {
+ await subjectManager.handleSubjectSubmit(e);
+ showNotification('Fach erfolgreich erstellt!', 'success');
+ } catch (error) {
+ showNotification(error.message || 'Fehler beim Erstellen des Fachs', 'error');
+ } finally {
+ submitButton.disabled = false;
+ submitButton.innerHTML = 'Speichern';
+ }
+ });
+ }
+});
+
+function showNotification(message, type = 'success') {
+ const notification = document.createElement('div');
+ notification.className = `fixed bottom-4 right-4 p-4 rounded-lg text-white ${
+ type === 'success' ? 'bg-green-500' : 'bg-red-500'
+ }`;
+ notification.textContent = message;
+ document.body.appendChild(notification);
+
+ gsap.to(notification, {
+ opacity: 0,
+ y: 20,
+ delay: 3,
+ duration: 0.5,
+ onComplete: () => notification.remove()
+ });
+}
+
+// Form submissions and other JavaScript functions
+// ... rest of your JavaScript code ...
diff --git a/TeacherDashboard/js/subjects/SubjectModel.js b/TeacherDashboard/js/subjects/SubjectModel.js
new file mode 100644
index 0000000..e0edaad
--- /dev/null
+++ b/TeacherDashboard/js/subjects/SubjectModel.js
@@ -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
+ };
+ }
+}
diff --git a/TeacherDashboard/js/subjects/SubjectStorage.js b/TeacherDashboard/js/subjects/SubjectStorage.js
new file mode 100644
index 0000000..1446f39
--- /dev/null
+++ b/TeacherDashboard/js/subjects/SubjectStorage.js
@@ -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));
+ }
+}
diff --git a/TeacherDashboard/js/subjects/colors.js b/TeacherDashboard/js/subjects/colors.js
new file mode 100644
index 0000000..81eb13b
--- /dev/null
+++ b/TeacherDashboard/js/subjects/colors.js
@@ -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
+ }));
+}
diff --git a/TeacherDashboard/js/subjects/subjectManager.js b/TeacherDashboard/js/subjects/subjectManager.js
new file mode 100644
index 0000000..f0723bf
--- /dev/null
+++ b/TeacherDashboard/js/subjects/subjectManager.js
@@ -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 => `
+
+
+ `).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 = `
+ Meine Fächer
+
+
+ `;
+ 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 = `
+
+
+
+
+
${subject.name}
+
${subject.description || ''}
+
+ `;
+ return div;
+ }
+}
diff --git a/TeacherDashboard/js/topics/TopicModel.js b/TeacherDashboard/js/topics/TopicModel.js
new file mode 100644
index 0000000..e69de29
diff --git a/TeacherDashboard/js/topics/topicManager.js b/TeacherDashboard/js/topics/topicManager.js
new file mode 100644
index 0000000..901e783
--- /dev/null
+++ b/TeacherDashboard/js/topics/topicManager.js
@@ -0,0 +1,178 @@
+import { SubjectStorage } from '../subjects/SubjectStorage.js';
+
+export class TopicManager {
+ constructor() {
+ this.subjectStorage = new SubjectStorage();
+ this.quill = null;
+ this.initializeEventListeners();
+ }
+
+ initializeEditor() {
+ const toolbarOptions = [
+ ['undo', 'redo'],
+ [{ 'header': [1, 2, false] }],
+ ['bold', 'italic', 'underline', 'strike'],
+ ['blockquote', 'code-block'],
+ [{ 'list': 'ordered'}, { 'list': 'bullet' }],
+ [{ 'script': 'sub'}, { 'script': 'super' }],
+ [{ 'indent': '-1'}, { 'indent': '+1' }],
+ ['link', 'image', 'formula'],
+ ['clean']
+ ];
+
+ const editorOptions = {
+ modules: {
+ toolbar: toolbarOptions,
+ keyboard: {
+ bindings: {
+ custom1: {
+ key: 'Z',
+ shortKey: true,
+ handler: () => this.undo()
+ },
+ custom2: {
+ key: 'Z',
+ shortKey: true,
+ shiftKey: true,
+ handler: () => this.redo()
+ },
+ custom3: {
+ key: 'Delete',
+ handler: () => this.deleteSelected()
+ }
+ }
+ },
+ history: {
+ delay: 1000,
+ maxStack: 500,
+ userOnly: true
+ }
+ },
+ theme: 'snow',
+ formats: [
+ 'header',
+ 'bold', 'italic', 'underline', 'strike',
+ 'list', 'bullet',
+ 'indent',
+ 'link', 'image',
+ 'code-block',
+ 'blockquote',
+ 'clean'
+ ]
+ };
+
+ this.quill = new Quill('#quillEditor', editorOptions);
+ this.quill.on('text-change', () => {
+ this.updatePreview();
+ });
+ }
+
+ undo() {
+ if (this.quill) {
+ this.quill.history.undo();
+ }
+ }
+
+ redo() {
+ if (this.quill) {
+ this.quill.history.redo();
+ }
+ }
+
+ deleteSelected() {
+ if (this.quill) {
+ const range = this.quill.getSelection();
+ if (range) {
+ if (range.length > 0) {
+ // Delete selected text/content
+ this.quill.deleteText(range.index, range.length);
+ } else {
+ // Delete current line if no selection
+ const [line] = this.quill.getLine(range.index);
+ const lineLength = line.length();
+ this.quill.deleteText(range.index - lineLength, lineLength);
+ }
+ }
+ }
+ }
+
+ async loadSubjectsIntoSelect() {
+ const select = document.getElementById('topicSubjectSelect');
+ if (!select) return;
+
+ // Clear existing options except the first placeholder
+ while (select.options.length > 1) {
+ select.remove(1);
+ }
+
+ try {
+ const subjects = await this.subjectStorage.getAllSubjects();
+ subjects.forEach(subject => {
+ const option = document.createElement('option');
+ option.value = subject.id;
+ option.textContent = subject.name;
+ select.appendChild(option);
+ });
+ } catch (error) {
+ console.error('Error loading subjects:', error);
+ }
+ }
+
+ initializeEventListeners() {
+ const form = document.getElementById('topicForm');
+ if (form) {
+ form.addEventListener('submit', (e) => this.handleTopicSubmit(e));
+ }
+ document.addEventListener('openTopicModal', () => {
+ this.loadSubjectsIntoSelect();
+ if (!this.quill) {
+ this.initializeEditor();
+ }
+ });
+ }
+
+ updatePreview() {
+ const content = this.quill.root.innerHTML;
+ const preview = document.getElementById('contentPreview');
+ const quillContent = document.getElementById('quillContent');
+
+ if (preview) {
+ // Preserve classes for styling while updating content
+ preview.innerHTML = content;
+ // Update hidden input with content
+ if (quillContent) {
+ quillContent.value = content;
+ }
+ // Re-render math if present
+ if (window.MathJax) {
+ MathJax.typeset([preview]);
+ }
+ // Highlight code blocks if any
+ if (window.Prism) {
+ Prism.highlightAllUnder(preview);
+ }
+ }
+ }
+
+ handleTopicSubmit(e) {
+ e.preventDefault();
+ const formData = new FormData(e.target);
+ const content = this.quill.root.innerHTML;
+ const subjectId = formData.get('subject');
+
+ if (!subjectId) {
+ throw new Error('Bitte wählen Sie ein Fach aus');
+ }
+
+ // Add your topic saving logic here
+
+ closeModal('topicModal');
+ }
+
+ clearEditor() {
+ if (this.quill) {
+ this.quill.setContents([]);
+ this.updatePreview();
+ }
+ }
+}
diff --git a/TeacherDashboard/styles/main.css b/TeacherDashboard/styles/main.css
new file mode 100644
index 0000000..ef53bce
--- /dev/null
+++ b/TeacherDashboard/styles/main.css
@@ -0,0 +1,184 @@
+:root {
+ --primary-color: #4f46e5;
+ --secondary-color: #3730a3;
+ --background-color: #f8fafc;
+ --text-color: #1e293b;
+ --accent-color: #818cf8;
+}
+
+.color-option {
+ width: 40px;
+ height: 40px;
+ border-radius: 12px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ border: 2px solid #e2e8f0;
+}
+
+.color-option:hover {
+ transform: scale(1.1);
+}
+
+.color-option.selected {
+ border: 2px solid var(--primary-color);
+ box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.3);
+}
+
+.modal {
+ opacity: 0;
+ visibility: hidden;
+ transition: all 0.3s ease;
+}
+
+.modal:not(.hidden) {
+ opacity: 1;
+ visibility: visible;
+}
+
+.modal > div {
+ transform: translateY(0);
+ transition: transform 0.3s ease, opacity 0.3s ease;
+}
+
+.modal.hidden > div {
+ transform: translateY(-20px);
+}
+
+/* Action Cards */
+.bg-white {
+ background-color: white;
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+.bg-white:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 25px rgba(0, 0, 0, 0.1);
+}
+
+button {
+ transition: all 0.2s ease;
+}
+
+button:disabled {
+ opacity: 0.7;
+ cursor: not-allowed;
+}
+
+/* Sidebar Styles */
+.sidebar {
+ background: linear-gradient(to bottom, var(--primary-color), var(--secondary-color));
+}
+
+.sidebar a {
+ display: flex;
+ align-items: center;
+ text-decoration: none;
+}
+
+.sidebar a:hover {
+ background-color: rgba(255, 255, 255, 0.1);
+}
+
+/* Form Styles */
+input[type="text"],
+textarea,
+select {
+ width: 100%;
+ padding: 0.75rem;
+ border-radius: 0.5rem;
+ border: 1px solid #e2e8f0;
+ transition: all 0.2s ease;
+}
+
+input[type="text"]:focus,
+textarea:focus,
+select:focus {
+ outline: none;
+ border-color: var(--primary-color);
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
+}
+
+/* Icon Selector Styles */
+.icon-option {
+ transition: all 0.2s ease;
+ color: var(--text-color);
+}
+
+.icon-option:hover {
+ transform: scale(1.05);
+ border-color: var(--primary-color);
+ color: var(--primary-color);
+}
+
+.icon-option.selected {
+ background-color: var(--primary-color);
+ color: white;
+ border-color: var(--primary-color);
+}
+
+/* Enhanced Quill content styling */
+.quill-content {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
+ line-height: 1.6;
+}
+
+.quill-content h1 {
+ font-size: 2em;
+ font-weight: 700;
+ margin: 1em 0 0.5em;
+ color: #111;
+ line-height: 1.2;
+}
+
+.quill-content h2 {
+ font-size: 1.5em;
+ font-weight: 600;
+ margin: 1em 0 0.5em;
+ color: #222;
+ line-height: 1.3;
+}
+
+.quill-content p {
+ margin: 0 0 1em;
+ color: #333;
+}
+
+.quill-content ul, .quill-content ol {
+ margin: 0 0 1em 1.5em;
+ padding: 0;
+}
+
+.quill-content ul {
+ list-style-type: disc;
+}
+
+.quill-content ol {
+ list-style-type: decimal;
+}
+
+.quill-content pre {
+ background: #f8f9fa;
+ padding: 1em;
+ border-radius: 6px;
+ margin: 0 0 1em;
+ overflow-x: auto;
+}
+
+.quill-content blockquote {
+ border-left: 4px solid #e5e7eb;
+ padding: 0.5em 0 0.5em 1em;
+ margin: 0 0 1em;
+ color: #4b5563;
+ font-style: italic;
+}
+
+.quill-content code {
+ background: #f3f4f6;
+ padding: 0.2em 0.4em;
+ border-radius: 4px;
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
+ font-size: 0.9em;
+ color: #e11d48;
+}
+
+/* Rest of your CSS styles */