Waldemar Schneider

IT-Systemintegrator, der sowohl die Produktionshalle als auch den Serverraum versteht.

© 2026 Waldemar Schneider

Portfolio
Portfolio-Website: Projektsuchfeld

Portfolio-Website: Projektsuchfeld

2026-06-05WebentwicklungAbgeschlossen & verifiziert
FlaskPythonJavaScriptjQueryJinja2CSSRegex

Projektübersicht

Die ursprüngliche Tag-Filter-Leiste der Portfolio-Website wurde durch ein Live-Suchfeld ersetzt. Gleichzeitig wurde die Pagination neu geschrieben, damit sie korrekt mit Suchergebnissen zusammenarbeitet.

1. Situation (Ausgangslage)

Die Portfolio-Startseite zeigte eine Leiste mit klickbaren Tag-Buttons zum Filtern der Projektkacheln. Das funktionierte, hatte aber ein strukturelles Skalierungsproblem: Bei 16 Projekten waren es bereits 46 Tags. Mit wachsender Projektzahl würde eine Wand aus 80 bis 100 Buttons entstehen, die für einen Personaler schwer zu nutzen ist. Ausserdem konnte die Suche nur nach explizit gesetzten Tags filtern, nicht nach Inhalten die zwar im Projekt vorkommen, aber nicht als Tag erfasst waren.

2. Task (Zielsetzung)

  • Skalierbares Suchsystem: Ein Suchfeld das mit beliebig vielen Projekten funktioniert, ohne dass die Oberfläche wächst.
  • Breitere Suche: Nicht nur Tags, sondern auch Titel, Teaser, Kategorie und die Kapitelüberschriften jedes Projekts durchsuchen.
  • Funktionierende Pagination: Die bestehende Pagination korrekt mit dem Suchergebnis verzahnen, damit die Seitennummerierung bei gefilterten Ergebnissen stimmt.

3. Action (Umsetzung)

A. Heading-Extraktion im Backend (Python/Flask)

In routes.py wurde die Funktion get_all_projects() erweitert: Beim Einlesen jeder .md-Projektdatei werden mit einem Regex alle H2- bis H6-Überschriften extrahiert und als lowercase-String ins Projekt-Dictionary aufgenommen. Das macht die Kapitelüberschriften für das Frontend als data-headings-Attribut zugänglich. Der Grund dafür: Technologien wie "Promtail" tauchen als Tag nicht auf, haben aber ein eigenes Kapitel im Text. Ohne diese Erweiterung wäre das Projekt bei der Suche danach nicht gefunden worden.

B. HTML-Template anpassen (Jinja2)

Die Tag-Button-Leiste wurde aus index.html entfernt und durch ein einzelnes Texteingabefeld ersetzt. Die Tags selbst bleiben als unsichtbares data-tags-Attribut auf jeder Kachel erhalten und werden weiterhin von der Suche ausgewertet. Die Kachel-Wrapper bekamen vier weitere Daten-Attribute: data-title, data-teaser, data-category und data-headings, alle lowercase damit die Suche ohne zusätzliche JavaScript-Konvertierung case-insensitiv funktioniert.

C. Such- und Pagination-Logik in JavaScript neu schreiben

Die gesamte Pagination- und Filter-Logik in main.js wurde ersetzt, unter Nutzung der bereits im Template eingebundenen jQuery-Bibliothek für DOM-Selektion und Iteration. Der Kern des Problems mit der alten Lösung: data-page-Attribute wurden beim Seiten-Laden durch Jinja2 fest gesetzt und blieben statisch. Sobald ein Filter die sichtbaren Kacheln änderte, stimmten die Seitenzahlen nicht mehr.

Die neue Lösung: Ein JavaScript-Array filteredCards hält immer die aktuelle Menge der sichtbaren Kacheln. applySearch() befüllt das Array bei jedem Tastendruck neu, rebuildPagination() baut die Seitennavigation auf Basis der Array-Länge neu auf, showPage() berechnet anhand des Array-Index welche Kacheln sichtbar sein sollen. Die Seiten-Navigation ist damit vollständig vom HTML-Markup entkoppelt.

D. CSS für Dark- und Light-Mode

Das Suchfeld-Styling wurde in main.css ergänzt. Das Template nutzt inverse CSS-Logik: Dark Mode ist der Default ohne Class, Light Mode wird durch body.light-mode aktiviert. Das Suchfeld-Styling musste beide Zustände explizit abdecken, weil color: inherit in diesem Fall nicht ausreichte.

4. Result (Ergebnis & Verifikation)

Das Suchfeld funktioniert live bei jedem Tastendruck, findet Projekte über alle fünf Felder korrekt und die Pagination zeigt bei gefilterten Ergebnissen die richtigen Kacheln. Alle sieben definierten Tests bestanden.

TestErgebnis
Leeres Suchfeld: alle Projekte sichtbarbestanden
Suche nach Technologie-Tag: nur passende Projektebestanden
Suche nach Kapitelüberschrift (kein Tag): Trefferbestanden
Pagination bei gefilterten Ergebnissen korrektbestanden
Dark Mode: Suchfeld-Text lesbarbestanden
Light Mode: Suchfeld-Text lesbarbestanden
Suchfeld leeren: alle Projekte zurückbestanden

Lessons Learned

  • Statische HTML-Attribute und dynamische Filter vertragen sich nicht: data-page Werte die beim Seitenaufruf fest gesetzt werden, werden durch einen Filter sofort inkonsistent. Array-basierter Index ist die saubere Lösung.
  • re.MULTILINE ist entscheidend für zeilenbasierte Regex: Ohne dieses Flag matcht ^ nur den Anfang des gesamten Strings, nicht jeden Zeilenanfang. Alle Überschriften ausser der ersten wären unsichtbar geblieben.
  • input statt change für Live-Suche: change feuert erst wenn das Eingabefeld verlassen wird. Für sofortige Rückmeldung bei jedem Tastendruck muss input verwendet werden.
  • Tags als Metadaten, nicht als UI-Element: Tags aus der sichtbaren Oberfläche zu entfernen, aber als Daten-Attribut zu behalten, löst das Skalierungsproblem ohne Informationsverlust.