Test: Lokale Entwicklungsumgebung eingerichtet

This commit is contained in:
Sven Lubenau 2025-09-12 17:36:30 +02:00
parent 44eb8792d3
commit e6f993bb0a
18 changed files with 1094 additions and 390 deletions

BIN
www/.DS_Store vendored Normal file

Binary file not shown.

1
www/Bundeslaender-repo Symbolic link
View File

@ -0,0 +1 @@
../Bundeslaender

View File

@ -0,0 +1,2 @@
/Bundeslaender/1_BW_Baden-Württemberg/3_Schuldienst/Texte/BW_SD_SM-1.md
/Bundeslaender/1_BW_Baden-Württemberg/3_Schuldienst/Texte/BW_SD_SM-2.md

View File

@ -0,0 +1,6 @@
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-1.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-3.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-4.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-5.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-6.md
/Bundeslaender/1_BW_Baden-Württemberg/3_Schuldienst/Texte/BW_SD_SM-1.md

View File

@ -0,0 +1,4 @@
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-4.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-5.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-6.md
/Bundeslaender/1_BW_Baden-Württemberg/3_Schuldienst/Texte/BW_SD_SM-1.md

View File

@ -0,0 +1 @@
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-4.md

View File

@ -0,0 +1,6 @@
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-4.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-5.md
/Bundeslaender/1_BW_Baden-Württemberg/2_ Vorbereitungsdienst/Texte/BW_VD_SM-1.md
/Bundeslaender/1_BW_Baden-Württemberg/2_ Vorbereitungsdienst/Texte/BW_VD_SM-2.md
/Bundeslaender/1_BW_Baden-Württemberg/3_Schuldienst/Texte/BW_SD_SM-1.md
/Bundeslaender/1_BW_Baden-Württemberg/3_Schuldienst/Texte/BW_SD_VL.md

View File

@ -0,0 +1,6 @@
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-4.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-5.md
/Bundeslaender/1_BW_Baden-Württemberg/2_ Vorbereitungsdienst/Texte/BW_VD_SM-1.md
/Bundeslaender/1_BW_Baden-Württemberg/2_ Vorbereitungsdienst/Texte/BW_VD_SM-2.md
/Bundeslaender/1_BW_Baden-Württemberg/3_Schuldienst/Texte/BW_SD_SM-1.md
/Bundeslaender/1_BW_Baden-Württemberg/3_Schuldienst/Texte/BW_SD_VL.md

View File

@ -0,0 +1,3 @@
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_GS.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SO.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_DF.md

View File

@ -0,0 +1,2 @@
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_DF.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-2.md

View File

@ -0,0 +1,3 @@
/Bundeslaender/1_BW_Baden-Württemberg/3_Schuldienst/Texte/BW_SD_WB_1.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_DF.md
/Bundeslaender/1_BW_Baden-Württemberg/3_Schuldienst/Texte/BW_SD_VL.md

View File

@ -0,0 +1,4 @@
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_DF.md
/Bundeslaender/1_BW_Baden-Württemberg/1_Studium/Texte/BW_HS_SM-2.md
/Bundeslaender/1_BW_Baden-Württemberg/2_ Vorbereitungsdienst/Texte/BW_VD_RE.md
/Bundeslaender/1_BW_Baden-Württemberg/3_Schuldienst/Texte/BW_SD_VL.md

View File

@ -0,0 +1,478 @@
// finder.js Logik für den Step-basierten Finder im Tab 2 mit YAML-Ausgabe
let steps = []; // Alle geladenen Schritte aus structure.yml
let answers = []; // User-Antworten
let selectedBundesland = ''; // Aktuelles Bundesland
let currentPath = []; // Aktueller Pfad durch den Entscheidungsbaum
// Lädt Finderstruktur aus YML und speichert sie global
async function loadFinderStructure() {
try {
const response = await fetch('Steuerungsdateien/finder.yml');
const text = await response.text();
const data = jsyaml.load(text);
steps = data.steps;
console.log('[DEBUG] Finderstruktur geladen:', steps);
resetFinder();
renderBundeslandStep();
} catch (err) {
console.error("Fehler beim Laden der structure.yml:", err);
}
}
// Setzt den Finder zurück
function resetFinder() {
answers = [];
selectedBundesland = '';
currentPath = ['step1'];
document.getElementById('result').style.display = 'none';
document.getElementById('dynamic-steps').innerHTML = '';
}
// Baut das initiale Bundesland-Auswahlfeld mit Arrow und Styling
function renderBundeslandStep() {
const step1 = steps.find(s => s.id === 'step1');
if (!step1) return;
const container = document.getElementById('dynamic-steps');
container.innerHTML = ''; // Reset
const div = document.createElement('div');
div.className = 'step active';
div.id = 'step1';
const label = document.createElement('label');
label.textContent = step1.frage;
div.appendChild(label);
// Erstelle den wrapper mit Klasse für bessere Auswählbarkeit
const wrapper = document.createElement('div');
wrapper.className = 'select-wrapper'; // NEU
wrapper.style.position = 'relative';
wrapper.style.display = 'inline-block'; // NEU
const select = document.createElement('select');
select.className = 'select purple auto-width';
select.id = 'bundesland-steps';
select.name = 'bundesland';
const defaultOpt = document.createElement('option');
defaultOpt.textContent = 'Bitte wählen';
defaultOpt.value = '';
select.appendChild(defaultOpt);
step1.options.forEach(opt => {
const option = document.createElement('option');
option.value = opt.value;
option.textContent = opt.label;
select.appendChild(option);
});
// Vorauswahl des Bundeslandes, falls vorhanden
if (selectedBundesland) {
select.value = selectedBundesland;
}
select.addEventListener('change', (e) => {
const val = e.target.value;
if (val !== '') {
// Wenn Bundesland geändert wird, Pfad neu berechnen und alle nachfolgenden Steps entfernen
recalculatePathFrom('step1', val);
onBundeslandSelected(val);
}
});
const arrow = document.createElement('div');
arrow.className = 'select-arrow';
wrapper.appendChild(select);
wrapper.appendChild(arrow);
div.appendChild(wrapper);
const info = document.createElement('div');
info.className = 'info';
info.textContent = step1.info;
div.appendChild(info);
container.appendChild(div);
setTimeout(() => {
resizeSelect(select);
}, 0);
}
// Wird aufgerufen, wenn das Bundesland gewählt wurde (step1)
function onBundeslandSelected(value) {
selectedBundesland = value;
answers[0] = value;
document.getElementById('result').style.display = 'none';
// Alle nachfolgenden Steps entfernen
removeStepsAfter('step1');
// Step 2 rendern
const step2 = steps.find(s => s.id === 'step2');
if (step2) renderStep(step2);
}
// Rendert einen Step (Frage + Optionen)
function renderStep(step) {
const container = document.getElementById('dynamic-steps');
// Prüfen, ob dieser Step bereits existiert
let stepElement = document.getElementById(step.id);
if (stepElement) {
// Falls der Step bereits existiert, nur Info anzeigen
const info = stepElement.querySelector('.info');
if (info) info.style.display = 'block';
// Falls der Step bereits existiert und eine Antwort hat, markiere den Button
const stepIndex = steps.findIndex(s => s.id === step.id);
const selectedValue = answers[stepIndex];
if (selectedValue) {
const buttons = stepElement.querySelectorAll('button');
buttons.forEach(btn => {
if (btn.dataset.value === selectedValue) {
btn.classList.add('selected');
} else {
btn.classList.remove('selected');
}
});
}
stepElement.scrollIntoView({ behavior: 'smooth' });
return;
}
// Neuen Step erstellen
const div = document.createElement('div');
div.className = 'step active';
div.id = step.id;
const frage = document.createElement('label');
frage.textContent = step.frage;
div.appendChild(frage);
const buttonGroup = document.createElement('div');
buttonGroup.className = 'button-group';
step.options.forEach(opt => {
const btn = document.createElement('button');
btn.type = 'button';
btn.className = 'button';
btn.textContent = opt.label;
btn.dataset.value = opt.value;
// Wenn bereits eine Antwort ausgewählt ist, markieren
const stepIndex = steps.findIndex(s => s.id === step.id);
if (answers[stepIndex] === opt.value) {
btn.classList.add('selected');
}
btn.onclick = () => {
// Vorher ausgewählte Buttons deselektieren
buttonGroup.querySelectorAll('button').forEach(b => b.classList.remove('selected'));
btn.classList.add('selected');
// Antwort speichern
const stepIndex = steps.findIndex(s => s.id === step.id);
answers[stepIndex] = opt.value;
// Info ausblenden
div.querySelector('.info').style.display = 'none';
// Pfad neu berechnen und alle nachfolgenden Steps entfernen
recalculatePathFrom(step.id, opt.value);
removeStepsAfter(step.id);
// Abhängig von der Option weitergehen oder Ergebnis anzeigen
if (opt.result) {
// Am Ende des Pfades - Ergebnis anzeigen
const code = buildResultCode();
loadResult(code);
} else if (opt.next) {
// Nächsten Step anzeigen
const nextStep = steps.find(s => s.id === opt.next);
if (nextStep) renderStep(nextStep);
}
};
buttonGroup.appendChild(btn);
});
div.appendChild(buttonGroup);
const info = document.createElement('div');
info.className = 'info';
info.textContent = step.info;
div.appendChild(info);
container.appendChild(div);
div.scrollIntoView({ behavior: 'smooth' });
// Step zum aktiven Pfad hinzufügen
if (!currentPath.includes(step.id)) {
currentPath.push(step.id);
}
}
// Berechnet den Pfad ausgehend von einem bestimmten Step neu
function recalculatePathFrom(stepId, selectedValue) {
const stepIndex = steps.findIndex(s => s.id === stepId);
// Aktualisiere den aktuellen Pfad (entferne alle nach dem geänderten Step)
currentPath = currentPath.slice(0, currentPath.indexOf(stepId) + 1);
// Aktualisiere die Antworten (behalte nur Antworten bis zum aktuellen Step)
answers = answers.slice(0, stepIndex + 1);
// Setze die ausgewählte Antwort
answers[stepIndex] = selectedValue;
console.log('[DEBUG] Neuer Pfad berechnet ab', stepId, 'Pfad:', currentPath, 'Antworten:', answers);
// Ergebnis ausblenden, da sich der Pfad geändert hat
document.getElementById('result').style.display = 'none';
}
// Entfernt alle Steps nach dem angegebenen Step aus dem DOM
function removeStepsAfter(stepId) {
const container = document.getElementById('dynamic-steps');
const stepElements = container.querySelectorAll('.step');
let removeFlag = false;
stepElements.forEach(el => {
if (removeFlag) {
container.removeChild(el);
}
if (el.id === stepId) {
removeFlag = true;
}
});
// Ergebnis ausblenden
document.getElementById('result').style.display = 'none';
}
// Generiert den Code für das Ergebnis aus den Antworten
function buildResultCode() {
// Bundesland-Code mapping
const bundeslandMapping = {
'BW': '1_BW', // Baden-Württemberg
'BY': '2_BY', // Bayern
'BE': '3_BE', // Berlin
'BB': '4_BB', // Brandenburg
'HB': '5_HB', // Bremen
'HH': '6_HH', // Hamburg
'HE': '7_HE', // Hessen
'MV': '8_MV', // Mecklenburg-Vorpommern
'NI': '9_NI', // Niedersachsen
'NW': '10_NW', // Nordrhein-Westfalen
'RP': '11_RP', // Rheinland-Pfalz
'SL': '12_SL', // Saarland
'SN': '13_SN', // Sachsen
'ST': '14_ST', // Sachsen-Anhalt
'SH': '15_SH', // Schleswig-Holstein
'TH': '16_TH' // Thüringen
};
console.log('[DEBUG] Alle Antworten vor Filterung:', answers);
// Stelle sicher, dass answers ein Array ist und alle Elemente definiert sind
const cleanAnswers = answers.filter(answer => answer !== undefined && answer !== null && answer !== '');
console.log('[DEBUG] Bereinigte Antworten:', cleanAnswers);
if (cleanAnswers.length === 0) {
console.error('[ERROR] Keine gültigen Antworten gefunden');
return 'error/no-answers';
}
const bundesland = bundeslandMapping[cleanAnswers[0]] || cleanAnswers[0];
// Spezielle Behandlung für HS (Hochschulstudium)
let restCode;
if (cleanAnswers[1] === 'HS') {
// Bei HS: HS-BA-1F oder HS-MA-2F
restCode = cleanAnswers.slice(1).join('-');
} else {
// Bei LA: LA-BA-1F oder LA-MA-2F
restCode = cleanAnswers.slice(1).join('-');
}
const code = `${bundesland}/${restCode}`;
console.log('[DEBUG] Finaler Code:', code);
return code;
}
// Ergebnis anzeigen am Ende des Flows
async function loadResult(code) {
// 1. Ermittle den Pfad zur .md-Datei-Liste (z.B. Bundeslaender/1_BW/BA-2F.md)
// 2. Lade die Datei mit den Pfaden zu den eigentlichen Texten
// 3. Lade alle .md-Dateien in der Reihenfolge, parse sie und zeige sie als <article> an
let codeFile = `Bundeslaender/${code}.md`;
const resultContainer = document.getElementById('result');
const mainSection = resultContainer.querySelector('.main-section');
mainSection.innerHTML = '';
// Hilfsfunktion: Markdown-Abschnitt parsen und als Article rendern
function renderMarkdownArticle(mdText) {
// Splitte in Abschnitte nach ##
const sections = mdText.split(/\n(?=## )/);
return sections.map(section => {
let lines = section.trim().split('\n');
if (!lines[0].startsWith('##')) return '';
let headline = lines[0].replace(/^## /, '');
let marginal = '';
let textStart = 1;
// Prüfe zweite Zeile auf Link
if (lines[1] && lines[1].startsWith('http')) {
const linkLine = lines[1];
// Prüfe ob es ein Markdown-Link mit Text ist: [Text](URL)
const markdownLinkMatch = linkLine.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
if (markdownLinkMatch) {
// Markdown-Link gefunden: [Text](URL)
const linkText = markdownLinkMatch[1];
const linkUrl = markdownLinkMatch[2];
marginal = `<blockquote class='marginal'><a href="${linkUrl}" target="_blank">${linkText}</a></blockquote>`;
} else {
// Nur URL ohne Text - Fallback verwenden
marginal = `<blockquote class='marginal'><a href="${linkLine}" target="_blank">Externer Link</a></blockquote>`;
}
textStart = 2;
}
let text = lines.slice(textStart).join('\n');
return `<article class="content-article">
<div class="layout">
<div class="main-content">
<h2>${headline}</h2>
<div class="text-content">${marked.parse(text)}</div>
</div>
<div class="sidebar">${marginal}</div>
</div>
</article>`;
}).join('');
}
// Lade die Datei mit den Pfaden zu den eigentlichen Texten
try {
const pfadRes = await fetch(codeFile);
if (!pfadRes.ok) throw new Error('Datei nicht gefunden: ' + codeFile);
const pfadText = await pfadRes.text();
const mdFiles = pfadText.split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#'));
let allArticles = '';
for (const mdFile of mdFiles) {
try {
// Pfad für TYPO3 fileadmin - verwende den Symlink
// Entferne führenden Slash falls vorhanden
const cleanPath = mdFile.startsWith('/') ? mdFile.substring(1) : mdFile;
// Ersetze Bundeslaender durch den Symlink
const fullPath = cleanPath.replace(/^Bundeslaender\//, 'Bundeslaender-repo/');
const mdRes = await fetch(fullPath);
if (!mdRes.ok) throw new Error('Datei nicht gefunden: ' + fullPath);
const mdText = await mdRes.text();
allArticles += renderMarkdownArticle(mdText);
} catch (err) {
allArticles += `<article class="content-article"><div class='main-content'><h2>Datei nicht gefunden</h2><div class='text-content'>${mdFile}</div></div></article>`;
}
}
mainSection.innerHTML = allArticles;
resultContainer.style.display = 'block';
resultContainer.scrollIntoView({ behavior: 'smooth' });
} catch (err) {
mainSection.innerHTML = `<article class="content-article"><div class='main-content'><h2>Fehler</h2><div class='text-content'>${err.message}</div></div></article>`;
resultContainer.style.display = 'block';
}
}
// Lädt und zeigt die zusätzlichen Abschnitte an
function loadAdditionalSections(sections, resultContainer) {
if (!resultContainer) {
console.error('[ERROR] Kein gültiger Container für zusätzliche Abschnitte');
return;
}
// Trennlinie hinzufügen vor den zusätzlichen Abschnitten
const divider = document.createElement('hr');
divider.className = 'section-divider';
resultContainer.appendChild(divider);
// Jeden zusätzlichen Abschnitt laden
sections.forEach((sectionCode, index) => {
const path = `data/finder/texte/${sectionCode}.yml`;
console.log(`[DEBUG] Lade zusätzlichen Abschnitt ${index + 1} von:`, path);
fetch(path)
.then(res => res.ok ? res.text() : null)
.then(txt => txt ? jsyaml.load(txt) : null)
.then(data => {
if (!data) {
console.warn(`[WARN] Zusätzlicher Abschnitt ${sectionCode} konnte nicht geladen werden.`);
return;
}
// Zusätzlichen Abschnitt hinzufügen
appendAdditionalSection(data, index + 1, sectionCode, resultContainer);
})
.catch(err => {
console.error(`[ERROR] Fehler beim Laden des zusätzlichen Abschnitts ${sectionCode}:`, err);
});
});
}
// Fügt einen zusätzlichen Abschnitt zum DOM hinzu
function appendAdditionalSection(data, index, sectionCode, resultContainer) {
if (!resultContainer) {
console.error('[ERROR] Kein gültiger Container zum Anhängen des zusätzlichen Abschnitts');
return;
}
// Neuen Abschnitt erstellen
const section = document.createElement('div');
section.className = 'additional-section';
section.id = `section-${sectionCode}`;
section.innerHTML = `
<h2>${data.Headline || `Zusätzliche Information ${index}`}</h2>
<div class="text-content">${data.Text || '...'}</div>
<div class="tags">${data.Tags || ''}</div>
<div class="marginal">${data.Marginal || ''}</div>
`;
resultContainer.appendChild(section);
}
// Fügt einen Reset-Button hinzu (optional)
function addResetButton() {
const container = document.getElementById('dynamic-steps').parentElement;
let resetBtn = document.getElementById('reset-finder');
if (!resetBtn) {
resetBtn = document.createElement('button');
resetBtn.id = 'reset-finder';
resetBtn.className = 'button secondary';
resetBtn.textContent = 'Neu starten';
resetBtn.onclick = () => {
resetFinder();
renderBundeslandStep();
if (typeof showTab === 'function') showTab('tab2');
};
container.appendChild(resetBtn);
}
}
// Initialisierung beim Seitenladen
window.addEventListener('DOMContentLoaded', () => {
loadFinderStructure();
addResetButton(); // Optional
observeSelectChanges();
});

View File

@ -0,0 +1,100 @@
steps:
- id: step1
frage: Bundesland wählen
info: Wähle dein Bundesland für die passende Empfehlung. Jedes Bundesland hat eigene Regelungen für Lehrerausbildung und -einstellung. Manche Bundesländer haben höheren Bedarf an Informatiklehrern. Informiere dich über spezifische Voraussetzungen in deinem Wunschbundesland.
code_digit: true
options:
- label: Baden-Württemberg
value: BW
- label: Bayern
value: BY
- label: Berlin
value: BE
- label: Brandenburg
value: BB
- label: Bremen
value: HB
- label: Hamburg
value: HH
- label: Hessen
value: HE
- label: Mecklenburg-Vorpommern
value: MV
- label: Niedersachsen
value: NI
- label: Nordrhein-Westfalen
value: NW
- label: Rheinland-Pfalz
value: RP
- label: Saarland
value: SL
- label: Sachsen
value: SN
- label: Sachsen-Anhalt
value: ST
- label: Schleswig-Holstein
value: SH
- label: Thüringen
value: TH
- id: step2
frage: Was bringst du mit?
info: Dein bisheriger Bildungsweg entscheidet über den Weg zum Informatiklehrer. Ein Hochschulstudium oder Lehramtstudium eröffnet den direktesten Weg. Aber auch mit Abitur oder Berufsausbildung gibt es Möglichkeiten durch Quer- oder Seiteneinstieg.
code_digit: true
options:
- label: Abgeschlossenes Hochschulstudium
value: HS
next: step3
- label: Lehramtstudium
value: LA
next: step4
- label: Allgemeine Hochschulreife (Abitur)
value: HSREIFE
result: true
- label: Abgeschlossene Berufsausbildung
value: AUSBILDUNG
result: true
- id: step3
frage: Hast du einen Bachelor- oder Masterabschluss?
info: Der Grad deines Hochschulabschlusses beeinflusst deine Einstiegsmöglichkeiten als Informatiklehrer. Mit einem Master hast du oft bessere Chancen und höhere Einstufung im Beamtenverhältnis. Ein Bachelor reicht für den Quereinstieg meist aus, ein Master wird aber bevorzugt.
code_digit: true
options:
- label: Bachelor (oder gleichwertig)
value: BA
next: step5
- label: Master (oder gleichwertig)
value: MA
next: step5
- id: step4
frage: Der Lehramtabschluss ist ein Bachelor- oder Masterabschluss oder das 2. Staatsexamen?
info: Der Grad deines Lehramtstudiums bestimmt deine Einstiegsmöglichkeiten. Mit einem Master oder 2. Staatsexamen hast du bessere Chancen auf eine direkte Einstellung. Ein Bachelor im Lehramt ermöglicht oft den Quereinstieg, erfordert aber möglicherweise zusätzliche Qualifikationen.
code_digit: true
options:
- label: Bachelor (oder gleichwertig)
value: BA
next: step5
- label: Master (oder gleichwertig)
value: MA
next: step5
- label: 2. Staatsexamen
value: EX
next: step5
- id: step5
frage: Weiviel Fächer studierst du?
info: Die Anzahl deiner studierten Fächer bestimmt den Weg ins Lehramt. Mit zwei Fächern bist du optimal aufgestellt für reguläres Lehramt. Ein Fach ermöglicht Quereinstieg, oft mit Nachqualifikation im zweiten Fach. Ohne passende Fächer sind Umwege über Weiterbildungen oder Zusatzstudium nötig.
code_digit: true
options:
- label: kein Fach
value: 0F
result: true
- label: ein Fach
value: 1F
result: true
- label: zwei Fächer
value: 2F
result: true

View File

@ -0,0 +1,27 @@
/**
* @license
* MyFonts Webfont Build ID 4697673, 2022-04-13T08:44:55-0400
*
* The fonts listed in this notice are subject to the End User License
* Agreement(s) entered into by the website owner. All other parties are
* explicitly restricted from using the Licensed Webfonts(s).
*
* You may obtain a valid license at the URLs below.
*
* Webfont: CalebGrotesk-Medium by Brenners Template
* URL: https://www.myfonts.com/fonts/brenners-template/caleb-grotesk/medium/
* Copyright: Copylight(c)2021, Brenners Template All rights reserved
*
*
*
* © 2022 MyFonts Inc
*/
/* @import must be at top of file, otherwise CSS will not work */
@import url("//hello.myfonts.net/count/47ae49");
@font-face {
font-family: "CalebGrotesk-Medium";
src: url('webFonts/CalebGroteskMedium/font.woff2') format('woff2'), url('webFonts/CalebGroteskMedium/font.woff') format('woff');
}

Binary file not shown.

View File

@ -0,0 +1,416 @@
.container {
}
.step {
font-family: sans-serif;
display: none;
background: #eeeeee;
padding: 15px;
border-radius: 0px;
font-size: 1rem;
opacity: 1;
transition: opacity 0.4s ease;
}
.step.active {
display: block;
background: #f4f4f4;
opacity: 1;
border-bottom: 5px solid white;
}
.step.completed {
/* Stil für abgeschlossene Steps, z.B. grüner Rand oder Haken-Icon */
display: block;
}
.step.inactive {
/* Abgedunkelter Stil für inaktive Steps */
opacity: 0.6;
}
.step {
transition: all 0.3s ease-in-out;
opacity: 1;
max-height: 500px;
overflow: hidden;
}
.step.removing {
opacity: 0;
max-height: 0;
margin: 0;
padding: 0;
}
button.selected {
/* Markierter Button */
background-color: #007bff;
color: white;
}
button[disabled] {
/* Deaktivierte Buttons */
cursor: not-allowed;
opacity: 0.5;
}
button.secondary {
font-size: 0.75rem;
color: grey;
border-color: grey;
padding: 5px 7px;
}
.step .info {
padding: 7px;
margin-top: 10px;
}
label {
margin-bottom: 10px;
display: block;
padding: 7px;
}
.button {
font-size: 1rem;
padding: 15px 22px;
margin: 5px;
cursor: pointer;
border: 1px solid #e07047;
color: #e07047;
background: none;
display: inline-block;
border-radius: 3px;
}
.button.selected,
.button.active {
background: #e07047;
color: white;
}
body {
-webkit-text-size-adjust: 100%;
font-size: 16px;
}
.content-article {
margin-bottom: 2em;
padding: 1em;
background: white;
font-family: 'Fira Sans', sans-serif;
font-weight: 300; /* Light */
font-size: 1.2em; /* Reduziert von 1.556em */
line-height: 1.5;
}
.content-article:last-child {
margin-bottom: 0;
}
.content-article h2 {
font-family: 'CalebGrotesk-Medium', sans-serif;
font-weight: 500;
}
.content-article a {
color: rgb(172, 112, 195);
text-decoration: none;
transition: color 0.3s ease;
position: relative;
padding-left: 1.2em;
}
.content-article a::before {
content: "↗";
position: absolute;
left: 0;
top: 0;
font-size: 0.7em;
opacity: 0.6;
transition: opacity 0.3s ease;
}
.content-article a:hover {
color: #5a4c9;
text-decoration: underline;
}
.content-article a:hover::before {
opacity: 1;
}
.layout {
display: flex;
gap: 20px;
background: white !important;
}
.main-content {
flex: 2;
}
.sidebar {
flex: 1;
padding: 10px;
border-radius: 5px;
}
select {
font-size: 1rem;
border: none;
padding: 5px 10px 5px 10px;
color: white;
cursor: pointer;
outline: none;
appearance: none;
-webkit-appearance: none;
position: relative;
}
select.select {
display: inline-flex;
}
select.auto-width {
width: auto;
min-width: 50px;
display: inline-block;
}
.select.purple {
background-color: #ab70c1;
border-radius: 0px;
}
.select.orange {
background-color: #e27046;
border-radius: 9999px;
}
.select.blue {
background: #527fe2;
border-radius: 50px;
color: white;
}
.select.green {
background: #31a46e;
color: white;
clip-path: polygon(0 0, 95% 0, 100% 50%, 95% 100%, 0 100%);
border: none;
}
.select-finder {
font-size: 1rem;
border: none;
padding: 5px 10px 5px 10px;
color: white;
cursor: pointer;
outline: none;
appearance: none;
-webkit-appearance: none;
position: relative;
background-color: #ab70c1;
border-radius: 0px;
}
.select-arrow::after {
content: "";
position: absolute;
pointer-events: none;
top: 50%;
right: 10px;
transform: translate(0, -50%);
width: 12px;
height: 12px;
background-color: #fff;
clip-path: polygon(50% 80%, 0 20%, 100% 20%);
}
.tab {
background-color: #f1f1f1;
display: none;
}
.tab.active {
display: block;
}
.meta {
font-size: 1rem !important;
font-weight: 500;
}
.personas-tableau {
display: grid;
grid-template-columns: 1fr 212px;
gap: 20px;
align-items: start;
font-family: sans-serif;
}
.personas-portrait {
display: grid;
grid-template-columns: 180px 1fr;
gap: 20px;
padding: 15px 15px 15px 0px;
}
.portrait-left img {
width: 100%;
max-width: 200px;
border-radius: 10px;
}
.info-right {
flex: 1;
}
.persona-head h2 {
font-size: 1.8rem;
margin: 0 0 0.3em;
}
.persona-head .subline {
font-style: italic;
color: #777;
}
.text {
margin-top: 1em;
line-height: 1.5;
}
.persona-list {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: repeat(3, auto);
gap: 5px;
background-color: white;
border-left: 5px solid white;
max-height: 3965px;
overflow-y: auto;
border-bottom: 5px solid white;
}
.persona {
text-align: center;
cursor: pointer;
transition: opacity 0.3s;
background-color: #f1f1f1;
padding: 10px;
}
.persona img {
width: 80px;
filter: grayscale(100%);
transition: filter 0.3s ease;
}
.persona:hover img {
filter: none;
}
.persona span {
display: block;
margin-top: 0.5em;
font-size: 0.9rem;
color: #333;
}
.recommendation {
padding: 15px;
border-radius: 4px;
border-top: 5px solid white;
background-color: white;
}
.recommendation .distinction {
font-weight: bold;
color: #e07047;
}
.tab-buttons {
display: flex;
background-color: white;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border-bottom: 2px solid #f1f1f1;
font-size: 1rem;
}
.button-tab {
padding: 10px 20px;
margin: 0;
border: none;
background-color: white;
cursor: pointer;
border-right: 4px solid white;
font-weight: bold;
color: #333;
transition: background 0.2s ease;
border-radius: 3px;
}
.button-tab:last-child {
border-right: none;
}
.button-tab:hover {
font-weight: 700;
background-color: #e07047;
color: white;
}
.button-tab.active {
background-color: #f1f1f1;
border-bottom: 2px solid #f1f1f1;
color: #e07047;
}
.section-divider {
margin: 2rem 0;
border: 0;
height: 1px;
background-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0));
}
.additional-section {
margin-top: 1.5rem;
padding-top: 1rem;
}
.additional-section h2 {
font-size: 1.5rem;
margin-bottom: 1rem;
color: #333;
}
.additional-section .text-content {
margin-bottom: 1rem;
line-height: 1.6;
}
.additional-section .tags {
margin-bottom: 0.5rem;
font-size: 0.9rem;
color: #666;
}
.additional-section .tags:not(:empty)::before {
content: "Tags: ";
font-weight: bold;
}
.additional-section .marginal {
font-size: 0.9rem;
color: #666;
padding-top: 0.5rem;
border-top: 1px solid #eee;
}

View File

@ -1,382 +1,15 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Schrittweiser Auswahlprozess</title>
<style>
body {
font-family: sans-serif;
background: #fafafa;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.step {
font-family: sans-serif;
display: none;
background: #eeeeee;
padding: 15px;
border-radius: 0px;
font-size: 1rem;
opacity: 1;
transition: opacity 0.4s ease;
}
.step.active {
display: block;
background: #f4f4f4;
opacity: 1;
border-bottom: 5px solid white;
}
.step.completed {
/* Stil für abgeschlossene Steps, z.B. grüner Rand oder Haken-Icon */
display: block;
}
.step.inactive {
/* Abgedunkelter Stil für inaktive Steps */
opacity: 0.6;
}
.step {
transition: all 0.3s ease-in-out;
opacity: 1;
max-height: 500px;
overflow: hidden;
}
.step.removing {
opacity: 0;
max-height: 0;
margin: 0;
padding: 0;
}
button.selected {
/* Markierter Button */
background-color: #007bff;
color: white;
}
button[disabled] {
/* Deaktivierte Buttons */
cursor: not-allowed;
opacity: 0.5;
}
button.secondary {
font-size: 0.75rem;
color: grey;
border-color: grey;
padding: 5px 7px;
}
.step .info {
padding: 7px;
margin-top: 10px;
}
label {
margin-bottom: 10px;
display: block;
padding: 7px;
}
.button {
font-size: 1rem;
padding: 15px 22px;
margin: 5px;
cursor: pointer;
border: 1px solid #e07047;
color: #e07047;
background: none;
display: inline-block;
border-radius: 3px;
}
.button.selected,
.button.active {
background: #e07047;
color: white;
}
.layout {
display: flex;
gap: 20px;
background: white !important;
}
.main-content {
flex: 2;
}
.sidebar {
flex: 1;
padding: 10px;
border-radius: 5px;
}
select {
font-size: 1rem;
border: none;
padding: 5px 10px 5px 10px;
color: white;
cursor: pointer;
outline: none;
appearance: none;
-webkit-appearance: none;
position: relative;
}
select.select {
display: inline-flex;
}
select.auto-width {
width: auto;
min-width: 50px;
display: inline-block;
}
.select.purple {
background-color: #ab70c1;
border-radius: 0px;
}
.select.orange {
background-color: #e27046;
border-radius: 9999px;
}
.select.blue {
background: #527fe2;
border-radius: 50px;
color: white;
}
.select.green {
background: #31a46e;
color: white;
clip-path: polygon(0 0, 95% 0, 100% 50%, 95% 100%, 0 100%);
border: none;
}
.select-finder {
font-size: 1rem;
border: none;
padding: 5px 10px 5px 10px;
color: white;
cursor: pointer;
outline: none;
appearance: none;
-webkit-appearance: none;
position: relative;
background-color: #ab70c1;
border-radius: 0px;
}
.select-arrow::after {
content: "";
position: absolute;
pointer-events: none;
top: 50%;
right: 10px;
transform: translate(0, -50%);
width: 12px;
height: 12px;
background-color: #fff;
clip-path: polygon(50% 80%, 0 20%, 100% 20%);
}
.tab {
background-color: #f1f1f1;
display: none;
}
.tab.active {
display: block;
}
.meta {
font-size: 1rem !important;
font-weight: 500;
}
.personas-tableau {
display: grid;
grid-template-columns: 1fr 212px;
gap: 20px;
align-items: start;
font-family: sans-serif;
}
.personas-portrait {
display: grid;
grid-template-columns: 180px 1fr;
gap: 20px;
padding: 15px 15px 15px 0px;
}
.portrait-left img {
width: 100%;
max-width: 200px;
border-radius: 10px;
}
.info-right {
flex: 1;
}
.persona-head h2 {
font-size: 1.8rem;
margin: 0 0 0.3em;
}
.persona-head .subline {
font-style: italic;
color: #777;
}
.text {
margin-top: 1em;
line-height: 1.5;
}
.persona-list {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: repeat(3, auto);
gap: 5px;
background-color: white;
border-left: 5px solid white;
max-height: 3965px;
overflow-y: auto;
border-bottom: 5px solid white;
}
.persona {
text-align: center;
cursor: pointer;
transition: opacity 0.3s;
background-color: #f1f1f1;
padding: 10px;
}
.persona img {
width: 80px;
filter: grayscale(100%);
transition: filter 0.3s ease;
}
.persona:hover img {
filter: none;
}
.persona span {
display: block;
margin-top: 0.5em;
font-size: 0.9rem;
color: #333;
}
.recommendation {
padding: 15px;
border-radius: 4px;
border-top: 5px solid white;
background-color: white;
}
.recommendation .distinction {
font-weight: bold;
color: #e07047;
}
.tab-buttons {
display: flex;
background-color: white;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border-bottom: 2px solid #f1f1f1;
font-size: 1rem;
}
.button-tab {
padding: 10px 20px;
margin: 0;
border: none;
background-color: white;
cursor: pointer;
border-right: 4px solid white;
font-weight: bold;
color: #333;
transition: background 0.2s ease;
border-radius: 3px;
}
.button-tab:last-child {
border-right: none;
}
.button-tab:hover {
font-weight: 700;
background-color: #e07047;
color: white;
}
.button-tab.active {
background-color: #f1f1f1;
border-bottom: 2px solid #f1f1f1;
color: #e07047;
}
.section-divider {
margin: 2rem 0;
border: 0;
height: 1px;
background-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0));
}
.additional-section {
margin-top: 1.5rem;
padding-top: 1rem;
}
.additional-section h2 {
font-size: 1.5rem;
margin-bottom: 1rem;
color: #333;
}
.additional-section .text-content {
margin-bottom: 1rem;
line-height: 1.6;
}
.additional-section .tags {
margin-bottom: 0.5rem;
font-size: 0.9rem;
color: #666;
}
.additional-section .tags:not(:empty)::before {
content: "Tags: ";
font-weight: bold;
}
.additional-section .marginal {
font-size: 0.9rem;
color: #666;
padding-top: 0.5rem;
border-top: 1px solid #eee;
}
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Werde Informatiklehrerin - Beratungstool</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans:wght@300&display=swap" rel="stylesheet">
<link rel="stylesheet" href="Steuerungsdateien/fonts.css">
<link rel="stylesheet" href="Steuerungsdateien/styles.css">
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
</head>
<body>
<div class="container">
@ -419,23 +52,25 @@ select.auto-width {
<!-- Finder Tab -->
<div class="tab tab2">
<form id="selectionForm">
<div id="dynamic-steps"></div>
<div id="result" style="display: none;">
<div class="main-section">
<h2 id="finder-headline">Empfehlung</h2>
<div id="finder-text-content" class="text-content">...</div>
<div id="finder-tags" class="tags"></div>
<div id="finder-marginal" class="marginal"></div>
</div>
<!-- Zusätzliche Abschnitte werden hier dynamisch eingefügt -->
</div>
</form>
</div>
<!-- Ergebnisse außerhalb des Tab-Containers -->
<div id="result" style="display: none;">
<div class="main-section">
<h2 id="finder-headline">Empfehlung</h2>
<div id="finder-text-content" class="text-content">...</div>
<div id="finder-tags" class="tags"></div>
<div id="finder-marginal" class="marginal"></div>
</div>
<!-- Zusätzliche Abschnitte werden hier dynamisch eingefügt -->
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/js-yaml@4.1.0/dist/js-yaml.min.js"></script>
<script src="data/personas.js"></script>
<script src="data/finder.js"></script>
<script src="Steuerungsdateien/finder.js"></script>
<script>
// Tabs anzeigen
function showTab(tabId) {
@ -443,8 +78,18 @@ select.auto-width {
document.querySelector(`.${tabId}`).classList.add('active');
document.querySelectorAll('.button-tab').forEach(btn => btn.classList.remove('active'));
document.querySelector(`.button-tab[onclick*="${tabId}"]`).classList.add('active');
}
</script>
// Wenn Finder-Tab aktiviert wird, lade die Struktur
if (tabId === 'tab2') {
loadFinderStructure();
}
}
// Initialisiere die Anwendung
document.addEventListener('DOMContentLoaded', function() {
// Lade den Finder beim Start
loadFinderStructure();
});
</script>
</body>
</html>