diff --git a/css/style.css b/css/style.css index fe451d0..95b7333 100644 --- a/css/style.css +++ b/css/style.css @@ -754,6 +754,473 @@ textarea { color: #ff1493; } +/* =========================== + Notenrechner DOM Version Styles + =========================== */ + +.calculator-tabs { + display: flex; + gap: 0.5rem; + margin: 1.5rem 0; + flex-wrap: wrap; +} + +.calculator-tabs .tab-btn { + padding: 0.8rem 1.5rem; + background: rgba(255, 105, 180, 0.1); + border: 2px solid rgba(255, 105, 180, 0.2); + border-radius: 12px; + color: #ff1493; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + font-size: 0.95rem; +} + +.calculator-tabs .tab-btn:hover { + background: rgba(255, 105, 180, 0.2); + border-color: #ff1493; +} + +.calculator-tabs .tab-btn.active { + background: linear-gradient(135deg, #ff1493 0%, #ff69b4 100%); + color: white; + border-color: #ff1493; +} + +.tab-content { + display: none; + animation: slideUp 0.5s ease-out; +} + +.tab-content.active { + display: block; +} + +.calculator-box { + background: rgba(255, 255, 255, 0.85); + border: 2px solid rgba(255, 105, 180, 0.2); + border-radius: 20px; + padding: 2rem; + box-shadow: 0 8px 32px rgba(255, 20, 147, 0.15); +} + +.calculator-box h3 { + color: #ff1493; + margin-bottom: 0.5rem; +} + +.calculator-box p { + color: #b8659c; + margin-bottom: 1.5rem; +} + +/* Simple Input Group */ +.simple-input-group { + display: grid; + grid-template-columns: 1fr 1fr auto; + gap: 1rem; + margin-bottom: 1.5rem; + align-items: end; +} + +.input-field { + display: flex; + flex-direction: column; +} + +.input-field label { + font-weight: 600; + color: #ff1493; + margin-bottom: 0.5rem; + font-size: 0.95rem; +} + +.form-input { + padding: 0.8rem; + border: 2px solid rgba(255, 105, 180, 0.2); + border-radius: 8px; + font-family: inherit; + font-size: 1rem; + color: #6b3a5f; + background: white; + transition: all 0.3s ease; +} + +.form-input:focus { + outline: none; + border-color: #ff1493; + box-shadow: 0 0 12px rgba(255, 20, 147, 0.2); +} + +.form-input::placeholder { + color: #b8659c; +} + +/* Result Box */ +.result-box { + background: rgba(255, 192, 203, 0.1); + border: 2px solid rgba(255, 105, 180, 0.2); + border-radius: 12px; + padding: 1.5rem; + margin-top: 1rem; + min-height: 80px; +} + +.error-text { + color: #dc143c; + font-weight: 600; + margin: 0; +} + +.grade-result-inline { + display: flex; + gap: 2rem; + align-items: center; + justify-content: center; +} + +.grade-note, +.grade-note-large { + font-weight: 700; + font-size: 1.5rem; +} + +.grade-percent { + font-weight: 600; + font-size: 1.2rem; + color: #b8659c; + background: rgba(255, 192, 203, 0.3); + padding: 0.5rem 1rem; + border-radius: 8px; +} + +.grade-result-detailed { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.result-header { + display: flex; + justify-content: space-between; + align-items: center; + padding-bottom: 1rem; + border-bottom: 2px solid rgba(255, 105, 180, 0.2); +} + +.result-header h4 { + margin: 0; + color: #ff1493; +} + +.grade-note-large { + font-size: 2rem; +} + +.result-details { + color: #6b3a5f; +} + +.result-details p { + margin: 0.3rem 0; + font-size: 0.95rem; +} + +/* Progress Bar */ +.progress-bar-container { + margin-top: 1.5rem; +} + +.progress-bar-background { + width: 100%; + height: 30px; + background: rgba(255, 192, 203, 0.2); + border: 2px solid rgba(255, 105, 180, 0.2); + border-radius: 8px; + overflow: hidden; + margin-bottom: 0.5rem; +} + +.progress-bar-fill { + height: 100%; + transition: width 0.5s ease, background-color 0.3s ease; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 600; + font-size: 0.9rem; +} + +.progress-text { + text-align: center; + color: #6b3a5f; + font-weight: 600; + font-size: 0.9rem; + margin: 0; +} + +/* Grades Container DOM */ +.grades-container-dom { + display: flex; + flex-direction: column; + gap: 1rem; + margin-bottom: 1.5rem; +} + +.grade-input-group-dom { + animation: slideUp 0.4s ease-out; +} + +.grade-input-wrapper-dom { + display: flex; + align-items: center; + gap: 0.8rem; + background: rgba(255, 192, 203, 0.1); + padding: 1rem; + border-radius: 12px; + border: 2px solid rgba(255, 105, 180, 0.15); + transition: all 0.3s ease; +} + +.grade-input-wrapper-dom:focus-within { + border-color: rgba(255, 105, 180, 0.4); + background: rgba(255, 192, 203, 0.2); +} + +.grade-points-dom, +.grade-max-dom { + flex: 1; + padding: 0.8rem; + border: 1px solid rgba(255, 105, 180, 0.2); + border-radius: 8px; + font-size: 1rem; + font-family: inherit; + color: #6b3a5f; + background: white; + transition: all 0.3s ease; +} + +.grade-points-dom:focus, +.grade-max-dom:focus { + outline: none; + border-color: #ff1493; + box-shadow: 0 0 8px rgba(255, 20, 147, 0.2); +} + +.grade-points-dom::placeholder, +.grade-max-dom::placeholder { + color: #b8659c; +} + +.grade-separator { + font-weight: 600; + color: #ff69b4; + font-size: 1.2rem; +} + +.grade-result-dom { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.3rem; + min-width: 80px; +} + +.grade-note-dom { + font-weight: 700; + font-size: 1.1rem; + color: #6b3a5f; +} + +.grade-percent-dom { + font-weight: 600; + font-size: 0.9rem; + color: #b8659c; + background: rgba(255, 192, 203, 0.3); + padding: 0.3rem 0.6rem; + border-radius: 6px; +} + +.grade-remove-btn-dom { + background: none; + border: none; + font-size: 1.3rem; + cursor: pointer; + color: #ff69b4; + padding: 0.5rem; + transition: all 0.3s ease; + border-radius: 50%; +} + +.grade-remove-btn-dom:hover { + background: rgba(255, 20, 147, 0.1); + color: #ff1493; + transform: scale(1.2); +} + +/* Calculator Buttons */ +.calculator-buttons { + display: flex; + flex-direction: column; + gap: 0.8rem; + margin-top: 1.5rem; +} + +.btn-add, +.btn-calculate, +.btn-reset { + padding: 1rem 1.5rem; + border: none; + border-radius: 12px; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + text-transform: uppercase; + letter-spacing: 1px; +} + +.btn-add { + background: rgba(255, 105, 180, 0.2); + color: #ff1493; + border: 2px solid rgba(255, 105, 180, 0.3); +} + +.btn-add:hover { + background: rgba(255, 105, 180, 0.3); + border-color: #ff1493; + transform: translateY(-2px); +} + +.btn-calculate { + background: linear-gradient(135deg, #ff1493 0%, #ff69b4 100%); + color: white; + box-shadow: 0 4px 15px rgba(255, 20, 147, 0.3); +} + +.btn-calculate:hover { + transform: translateY(-3px); + box-shadow: 0 6px 20px rgba(255, 20, 147, 0.4); +} + +.btn-reset { + background: rgba(200, 100, 150, 0.15); + color: #b8659c; + border: 2px solid rgba(200, 100, 150, 0.3); +} + +.btn-reset:hover { + background: rgba(200, 100, 150, 0.25); + border-color: #b8659c; + transform: translateY(-2px); +} + +/* Results DOM */ +.results-list { + display: flex; + flex-direction: column; + gap: 0.8rem; +} + +.results-list h4 { + margin-bottom: 0.5rem; + color: #ff1493; +} + +.result-item-dom { + display: flex; + align-items: center; + gap: 1rem; + padding: 1rem; + background: rgba(255, 192, 203, 0.15); + border-radius: 10px; + border-left: 4px solid rgba(255, 105, 180, 0.3); + transition: all 0.3s ease; + animation: slideUp 0.5s ease-out; +} + +.result-item-dom:hover { + background: rgba(255, 192, 203, 0.25); + border-left-color: #ff1493; + transform: translateX(5px); +} + +.result-number { + font-weight: 700; + color: #ff1493; + min-width: 40px; +} + +.result-details { + flex: 1; + color: #6b3a5f; + font-weight: 500; +} + +.result-grade-dom { + font-weight: 700; + font-size: 1.1rem; + padding: 0.5rem 1rem; + background: rgba(255, 255, 255, 0.5); + border-radius: 8px; + min-width: 120px; + text-align: center; +} + +/* Average Box DOM */ +.average-box-dom { + background: linear-gradient(135deg, rgba(255, 192, 203, 0.2) 0%, rgba(255, 160, 180, 0.1) 100%); + border: 2px solid rgba(255, 105, 180, 0.3); + border-radius: 15px; + padding: 1.5rem; + text-align: center; + animation: slideUp 0.6s ease-out; + box-shadow: 0 4px 15px rgba(255, 20, 147, 0.1); + margin-top: 1rem; +} + +.average-box-dom h4 { + margin-bottom: 1rem; + color: #ff1493; +} + +.average-display-dom { + display: flex; + align-items: center; + justify-content: center; + gap: 1.5rem; + margin: 1rem 0; +} + +.average-percent-dom { + font-size: 2.5rem; + font-weight: 800; + color: #ff1493; + background: rgba(255, 192, 203, 0.2); + width: 100px; + height: 100px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; +} + +.average-note-dom { + font-size: 1.8rem; + font-weight: 700; +} + +.average-details-dom { + margin-top: 1rem; + color: #b8659c; + font-weight: 500; + font-size: 0.95rem; +} + + + /* Grade Scale Table */ .grade-scale-table { width: 100%; @@ -1578,6 +2045,23 @@ textarea { width: 100%; } + .simple-input-group { + grid-template-columns: 1fr; + gap: 0.8rem; + } + + .simple-input-group .btn-calculate { + width: 100%; + } + + .calculator-tabs { + flex-direction: column; + } + + .calculator-tabs .tab-btn { + width: 100%; + } + .stats-grid { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 0.8rem; diff --git a/js/notenrechner-dom.js b/js/notenrechner-dom.js new file mode 100644 index 0000000..b70ac0b --- /dev/null +++ b/js/notenrechner-dom.js @@ -0,0 +1,436 @@ +/** + * Notenrechner DOM-Version + * Moderne JavaScript DOM-Manipulation mit addEventListener + * David & Karo - EIS Projekt + */ + +// Notenmaßstab definieren +const NOTENMASSTAB = { + 'sehr gut': { min: 90, max: 100, color: '#ff1493' }, + 'gut': { min: 75, max: 89, color: '#ff69b4' }, + 'befriedigend': { min: 60, max: 74, color: '#ffa500' }, + 'ausreichend': { min: 50, max: 59, color: '#ff8c00' }, + 'nicht bestanden': { min: 0, max: 49, color: '#dc143c' } +}; + +/** + * Berechnet die Note basierend auf der Punktzahl + * @param {number} punkte - Erreichte Punktzahl + * @param {number} maxPunkte - Maximale Punktzahl (default: 100) + * @returns {object} - Enthält Note, Prozentage und Details + */ +function berechneNote(punkte, maxPunkte = 100) { + // Eingabe validieren + punkte = parseFloat(punkte); + maxPunkte = parseFloat(maxPunkte); + + if (isNaN(punkte) || isNaN(maxPunkte)) { + return { + note: 'Fehler', + prozent: 0, + valid: false, + nachricht: 'Bitte geben Sie Zahlen ein!' + }; + } + + if (maxPunkte <= 0) { + return { + note: 'Fehler', + prozent: 0, + valid: false, + nachricht: 'Maximale Punktzahl muss größer als 0 sein!' + }; + } + + if (punkte < 0 || punkte > maxPunkte) { + return { + note: 'Fehler', + prozent: 0, + valid: false, + nachricht: `Punkte müssen zwischen 0 und ${maxPunkte} liegen!` + }; + } + + // Prozentage berechnen + const prozent = Math.round((punkte / maxPunkte) * 100); + + // Note basierend auf Prozentage bestimmen + let note = 'nicht bestanden'; + let noteColor = '#dc143c'; + + for (const [noteText, range] of Object.entries(NOTENMASSTAB)) { + if (prozent >= range.min && prozent <= range.max) { + note = noteText; + noteColor = range.color; + break; + } + } + + return { + note: note, + prozent: prozent, + punkte: punkte, + maxPunkte: maxPunkte, + valid: true, + color: noteColor, + nachricht: `${punkte} von ${maxPunkte} Punkten (${prozent}%) = ${note}` + }; +} + +/** + * Validiert die Eingabe + */ +function validateInput(value, maxValue = 100) { + if (value === '' || value === null) { + return { valid: false, error: 'Bitte geben Sie eine Punktzahl ein!' }; + } + + const num = parseFloat(value); + + if (isNaN(num)) { + return { valid: false, error: 'Bitte geben Sie eine Zahl ein!' }; + } + + if (num < 0 || num > maxValue) { + return { valid: false, error: `Punktzahl muss zwischen 0 und ${maxValue} liegen!` }; + } + + return { valid: true }; +} + +// Warte bis DOM geladen ist +document.addEventListener('DOMContentLoaded', function() { + // Simple Notenrechner + const simplePointsInput = document.getElementById('simple-points'); + const simpleMaxInput = document.getElementById('simple-max'); + const simpleCalculateBtn = document.getElementById('simple-calculate-btn'); + const simpleResult = document.getElementById('simple-result'); + const simpleProgressBar = document.getElementById('simple-progress-bar'); + + // Multiple Notenrechner + const addGradeBtn = document.getElementById('add-grade-btn'); + const multipleCalculateBtn = document.getElementById('multiple-calculate-btn'); + const multipleResetBtn = document.getElementById('multiple-reset-btn'); + const gradesContainer = document.getElementById('grades-container'); + const multipleResult = document.getElementById('multiple-result'); + const multipleAverage = document.getElementById('multiple-average'); + + // Simple Grade Calculator Event Listener + if (simpleCalculateBtn && simplePointsInput) { + simpleCalculateBtn.addEventListener('click', function() { + calculateSimpleGrade(); + }); + + // Enter-Taste auch zum Berechnen verwenden + simplePointsInput.addEventListener('keypress', function(event) { + if (event.key === 'Enter') { + calculateSimpleGrade(); + } + }); + + // Live-Berechnung während des Tippens + simplePointsInput.addEventListener('input', function() { + updateSimpleGradeLive(); + }); + + simpleMaxInput.addEventListener('input', function() { + updateSimpleGradeLive(); + }); + } + + // Multiple Grade Calculator Event Listener + if (addGradeBtn) { + addGradeBtn.addEventListener('click', function() { + addGradeInput(); + }); + } + + if (multipleCalculateBtn) { + multipleCalculateBtn.addEventListener('click', function() { + calculateMultipleGrades(); + }); + } + + if (multipleResetBtn) { + multipleResetBtn.addEventListener('click', function() { + resetMultipleCalculator(); + }); + } + + // Initiale Grade hinzufügen + if (gradesContainer) { + addGradeInput(); + } + + /** + * Berechnet einfache Note und zeigt Ergebnis + */ + function calculateSimpleGrade() { + const points = simplePointsInput.value; + const max = simpleMaxInput.value || 100; + + // Validierung + const validation = validateInput(points, max); + if (!validation.valid) { + showSimpleError(validation.error); + return; + } + + // Berechnung + const result = berechneNote(parseFloat(points), parseFloat(max)); + + if (!result.valid) { + showSimpleError(result.nachricht); + return; + } + + // Erfolgreiche Anzeige + showSimpleSuccess(result); + } + + /** + * Live-Aktualisierung während des Tippens + */ + function updateSimpleGradeLive() { + const points = simplePointsInput.value; + const max = simpleMaxInput.value || 100; + + if (points === '') { + simpleResult.innerHTML = ''; + simpleProgressBar.style.display = 'none'; + return; + } + + const validation = validateInput(points, max); + if (!validation.valid) { + simpleResult.innerHTML = `

⚠️ ${validation.error}

`; + simpleProgressBar.style.display = 'none'; + return; + } + + const result = berechneNote(parseFloat(points), parseFloat(max)); + if (result.valid) { + simpleResult.innerHTML = ` +
+ ${result.note} + ${result.prozent}% +
+ `; + updateProgressBar(result.prozent, result.color); + } + } + + /** + * Fehleranzeige mit rotem Hintergrund + */ + function showSimpleError(errorMessage) { + simplePointsInput.style.borderColor = 'red'; + simplePointsInput.style.backgroundColor = 'rgba(220, 20, 60, 0.1)'; + simpleResult.innerHTML = `

❌ ${errorMessage}

`; + simpleProgressBar.style.display = 'none'; + + // Reset nach 2 Sekunden + setTimeout(() => { + simplePointsInput.style.borderColor = ''; + simplePointsInput.style.backgroundColor = ''; + }, 2000); + } + + /** + * Erfolgreiche Anzeige mit Progressbar + */ + function showSimpleSuccess(result) { + simplePointsInput.style.borderColor = 'green'; + simplePointsInput.style.backgroundColor = 'rgba(34, 197, 94, 0.1)'; + + simpleResult.innerHTML = ` +
+
+

📊 Ergebnis:

+ ${result.note} +
+
+

Punkte: ${result.punkte} / ${result.maxPunkte}

+

Prozentage: ${result.prozent}%

+
+
+ `; + + updateProgressBar(result.prozent, result.color); + + // Reset nach 3 Sekunden + setTimeout(() => { + simplePointsInput.style.borderColor = ''; + simplePointsInput.style.backgroundColor = ''; + }, 3000); + } + + /** + * Aktualisiert die Progressbar + */ + function updateProgressBar(percent, color) { + simpleProgressBar.style.display = 'block'; + simpleProgressBar.innerHTML = ` +
+
+
+

${percent}% Complete

+ `; + } + + /** + * Neue Grade-Input-Zeile hinzufügen (Multiple) + */ + function addGradeInput() { + if (!gradesContainer) return; + + const gradeId = Date.now(); + const gradeDiv = document.createElement('div'); + gradeDiv.className = 'grade-input-group-dom'; + gradeDiv.id = `grade-${gradeId}`; + + gradeDiv.innerHTML = ` +
+ + / + +
+ - + 0% +
+ +
+ `; + + gradesContainer.appendChild(gradeDiv); + + // Event Listener für neue Eingabe + const pointsInput = gradeDiv.querySelector('.grade-points-dom'); + const maxInput = gradeDiv.querySelector('.grade-max-dom'); + const removeBtn = gradeDiv.querySelector('.grade-remove-btn-dom'); + const noteSpan = gradeDiv.querySelector('.grade-note-dom'); + const percentSpan = gradeDiv.querySelector('.grade-percent-dom'); + + function updateGradeLive() { + const points = parseFloat(pointsInput.value) || 0; + const max = parseFloat(maxInput.value) || 100; + + if (max > 0 && points >= 0 && points <= max) { + const result = berechneNote(points, max); + if (result.valid) { + noteSpan.textContent = result.note; + percentSpan.textContent = result.prozent + '%'; + noteSpan.style.color = result.color; + } + } else { + noteSpan.textContent = '-'; + percentSpan.textContent = '0%'; + } + } + + pointsInput.addEventListener('input', updateGradeLive); + maxInput.addEventListener('input', updateGradeLive); + + removeBtn.addEventListener('click', function() { + gradeDiv.remove(); + }); + + pointsInput.focus(); + } + + /** + * Berechnet mehrere Noten + */ + function calculateMultipleGrades() { + const gradeInputs = gradesContainer.querySelectorAll('.grade-input-group-dom'); + const noten = []; + + gradeInputs.forEach(input => { + const points = parseFloat(input.querySelector('.grade-points-dom').value); + const max = parseFloat(input.querySelector('.grade-max-dom').value); + + if (!isNaN(points) && !isNaN(max) && max > 0) { + const result = berechneNote(points, max); + if (result.valid) { + noten.push(result); + } + } + }); + + if (noten.length === 0) { + multipleResult.innerHTML = `

⚠️ Bitte füllen Sie mindestens eine Note aus!

`; + multipleAverage.innerHTML = ''; + return; + } + + // Einzelnoten anzeigen + let resultHTML = '

📊 Ihre Noten:

'; + noten.forEach((note, index) => { + resultHTML += ` +
+ #${index + 1} + ${note.punkte} / ${note.maxPunkte} (${note.prozent}%) + ${note.note} +
+ `; + }); + resultHTML += '
'; + multipleResult.innerHTML = resultHTML; + + // Durchschnitt berechnen + if (noten.length > 1) { + const durchschnittProzent = Math.round( + noten.reduce((sum, n) => sum + n.prozent, 0) / noten.length + ); + + let durchschnittNote = 'nicht bestanden'; + let durchschnittColor = '#dc143c'; + for (const [noteText, range] of Object.entries(NOTENMASSTAB)) { + if (durchschnittProzent >= range.min && durchschnittProzent <= range.max) { + durchschnittNote = noteText; + durchschnittColor = range.color; + break; + } + } + + multipleAverage.innerHTML = ` +
+

📈 Durchschnitt:

+
+
${durchschnittProzent}%
+
${durchschnittNote}
+
+

Von ${noten.length} Note(n)

+
+ `; + + // Console Ausgabe + console.log(`Durchschnitt: ${durchschnittProzent}% = ${durchschnittNote}`); + } else { + multipleAverage.innerHTML = ''; + } + } + + /** + * Setzt Multiple Grade Calculator zurück + */ + function resetMultipleCalculator() { + gradesContainer.innerHTML = ''; + multipleResult.innerHTML = ''; + multipleAverage.innerHTML = ''; + addGradeInput(); + } +}); diff --git a/notenrechner.html b/notenrechner.html index 8b4c1e4..199e5a4 100644 --- a/notenrechner.html +++ b/notenrechner.html @@ -46,12 +46,16 @@

Geben Sie Ihre erreichten Punkte und die maximale Punktzahl ein. Der Rechner berechnet automatisch den Prozentsatz.

-

2️⃣ Mehrere Noten

+

2️⃣ Live-Berechnung

+

Das Ergebnis wird direkt auf der Seite angezeigt - ohne Dialoge! Moderne DOM-Manipulation mit JavaScript.

+
+
+

3️⃣ Mehrere Noten

Fügen Sie mehrere Noten hinzu, um einen Durchschnitt zu berechnen. Perfekt für Prüfungsvorbereitung!

-

3️⃣ Sofort Feedback

-

Sehen Sie sofort, welche Note Sie erhalten – mit Prozentanzeige und hilfreichen Farben.

+

4️⃣ Visuelle Rückmeldung

+

Farbige Progressbars und Fehlerbehandlung mit rotem Hintergrund beim Input. Sofort Feedback!

@@ -97,43 +101,88 @@
-

🧮 Interaktiver Notenrechner

+

🧮 Notenrechner – DOM-Version

-
-
-

Gebe deine Noten ein:

+ +
+ + +
+ + +
+
+

Einfache Notenberechnung

+

Geben Sie eine Punktzahl ein und sehen Sie sofort das Ergebnis auf der Seite!

-
+
+
+ + +
+ +
+ + +
+ + +
+ +
+
+
+
+ + +
+
+

Mehrere Noten berechnen

+

Geben Sie mehrere Noten ein – der Durchschnitt wird automatisch berechnet!

+ +
- - - + + +
-
-
-
- -
-
- -
+
+
-

💡 Tipps & Tricks

+

💡 Moderne DOM-Manipulation mit JavaScript

@@ -143,7 +192,27 @@ - + +