diff --git a/README.md b/README.md index f285481..e825b06 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,11 @@ Rein manuelle Pflege: Sidebar links = Projekte, Hauptbereich = Feature-Cards. Markdown-Dateien unter `daten//.md` — Projekt = Ordner, die Datei ist die Wahrheit. Der Editor bearbeitet immer den rohen Text; geparst wird nur für die Anzeige. -Format (Marker allein auf einer Zeile; `` ist wiederholbar, `` -und `` gehören zur davorstehenden Funktion; Trennzeilen aus `---` sind Optik): +Format (Marker allein auf einer Zeile; `` ist wiederholbar; ``, +`` und `` nach einer Funktion gehören zu ihr — `ziel`/`regeln` +vor der ersten Funktion gehören zur Karte; regeln/testen: je eine `- `-Zeile pro Eintrag; +``-Blöcke aus dem Alt-Format werden zu Zeilen zusammengeführt; +Trennzeilen aus `---` sind Optik): ```markdown @@ -24,18 +27,19 @@ kern Kurzer Satz, was das Ziel ist. Anmeldung mit E-Mail - -Passwort nie loggen - + +- Passwort nie loggen + - Formular öffnen - Daten eingeben Abmeldung ``` -Funktionen erscheinen als Titelliste; Regeln und Flow zeigt die Karte erst beim Hover über -die Funktion. Text vor dem ersten Marker, Inhalt unbekannter Marker und verwaiste -regel/flow-Blöcke werden nicht angezeigt, aber beim Speichern erhalten. Bearbeitet wird live auf +Funktionen erscheinen als Titelliste; Regeln und Testen zeigt die ausführliche Ansicht. +Text vor dem ersten Marker, Inhalt unbekannter Marker und verwaiste +regeln/testen-Blöcke (auch Alt-Marker `flow`) werden nicht angezeigt, aber beim Speichern +erhalten. Bearbeitet wird live auf der Karte (Klick ins Feld, Verlassen speichert, Escape verwirft); jedes Speichern setzt die Datei neu zusammen. Titeländerungen benennen die Datei passend um. diff --git a/backend/parser.py b/backend/parser.py index 59058e8..296fc81 100644 --- a/backend/parser.py +++ b/backend/parser.py @@ -1,9 +1,11 @@ """Zerlegt den rohen Feature-Text in Sektionen — nur für die Anzeige. Format: titel (eine Zeile), art, ziel, dann wiederholbare -Blöcke; -- und -Blöcke gehören zur davorstehenden Funktion. -Präambel, unbekannte Marker und verwaiste regel/flow-Blöcke landen in `sonstiges` -(wird nicht angezeigt, aber beim Speichern erhalten). +- und -Blöcke (je eine `- `-Zeile pro Eintrag) gehören zur +davorstehenden Funktion. Alt-Format wird weiter gelesen: -Blöcke (einer je +Regel) und (heute testen) werden zusammengeführt. Präambel, unbekannte +Marker und verwaiste Blöcke landen in `sonstiges` (wird nicht angezeigt, aber beim +Speichern erhalten). Trennzeilen aus Bindestrichen (---) sind reine Optik und werden ignoriert. """ @@ -36,6 +38,7 @@ def zerlege(roh: str) -> dict: titel = [] ziel = [] + regeln = [] funktionen = [] sonstiges = [] art = [] @@ -45,18 +48,22 @@ def zerlege(roh: str) -> dict: elif schluessel == "art": art.append(text) elif schluessel == "ziel": - ziel.append(text) + # vor der ersten Funktion: Karten-Ziel, danach: Ziel der Funktion + (funktionen[-1]["ziel"] if funktionen else ziel).append(text) elif schluessel == "funktion": - funktionen.append({"text": text, "regeln": [], "flow": []}) - elif schluessel == "regel" and funktionen: - funktionen[-1]["regeln"].append(text) - elif schluessel == "flow" and funktionen: - funktionen[-1]["flow"].append(text) - else: # Präambel, unbekannter Marker, regel/flow ohne funktion + funktionen.append({"text": text, "ziel": [], "regeln": [], "testen": []}) + elif schluessel in ("regel", "regeln"): + # vor der ersten Funktion: Karten-Regeln, danach: Regeln der Funktion + (funktionen[-1]["regeln"] if funktionen else regeln).append(text) + elif schluessel in ("flow", "testen") and funktionen: + funktionen[-1]["testen"].append(text) + else: # Präambel, unbekannter Marker, regeln/testen ohne funktion sonstiges.append(text) for f in funktionen: - f["flow"] = "\n".join(f["flow"]) + f["ziel"] = "\n\n".join(f["ziel"]) + f["regeln"] = "\n".join(f["regeln"]) + f["testen"] = "\n".join(f["testen"]) # Titel ist eine Zeile: erste nicht-leere titel_zeilen = [z.strip() for t in titel for z in t.splitlines() if z.strip()] @@ -65,6 +72,7 @@ def zerlege(roh: str) -> dict: "titel": titel_zeilen[0] if titel_zeilen else "", "art": "optional" if art and art[0].strip().lower() == "optional" else "kern", "ziel": "\n\n".join(ziel), + "regeln": "\n".join(regeln), "funktionen": funktionen, "sonstiges": "\n\n".join(sonstiges), } diff --git a/backend/tests/test_parser.py b/backend/tests/test_parser.py index fe8fcaa..4fcacff 100644 --- a/backend/tests/test_parser.py +++ b/backend/tests/test_parser.py @@ -11,11 +11,10 @@ Nutzer können sich anmelden. ---------------------------------------- Anmeldung mit E-Mail - -Passwort nie loggen - -Sperre nach 5 Fehlversuchen - + +- Passwort nie loggen +- Sperre nach 5 Fehlversuchen + - Formular öffnen - Daten eingeben @@ -31,16 +30,33 @@ def test_alle_sektionen(): assert s["funktionen"] == [ { "text": "Anmeldung mit E-Mail", - "regeln": ["Passwort nie loggen", "Sperre nach 5 Fehlversuchen"], - "flow": "- Formular öffnen\n- Daten eingeben", + "ziel": "", + "regeln": "- Passwort nie loggen\n- Sperre nach 5 Fehlversuchen", + "testen": "- Formular öffnen\n- Daten eingeben", }, - {"text": "Abmeldung", "regeln": [], "flow": ""}, + {"text": "Abmeldung", "ziel": "", "regeln": "", "testen": ""}, ] -def test_mehrere_flow_bloecke_werden_verbunden(): - s = zerlege("\nX\n\n- a\n\n- b\n") - assert s["funktionen"][0]["flow"] == "- a\n- b" +def test_ziel_nach_funktion_gehoert_zur_funktion(): + s = zerlege("\nKarte\n\nX\n\nFunktion\n") + assert s["ziel"] == "Karte" + assert s["funktionen"][0]["ziel"] == "Funktion" + + +def test_mehrere_testen_bloecke_werden_verbunden(): + s = zerlege("\nX\n\n- a\n\n- b\n") + assert s["funktionen"][0]["testen"] == "- a\n- b" + + +def test_alter_flow_marker_wird_gelesen(): + s = zerlege("\nX\n\n- a\n") + assert s["funktionen"][0]["testen"] == "- a" + + +def test_alte_regel_bloecke_werden_zusammengefuehrt(): + s = zerlege("\nX\n\na\n\nb\n") + assert s["funktionen"][0]["regeln"] == "a\nb" def test_trenner_zeilen_werden_ignoriert(): @@ -59,10 +75,16 @@ def test_unbekannter_marker_landet_in_sonstiges(): assert s["sonstiges"] == "Geheim" -def test_regel_und_flow_ohne_funktion_landen_in_sonstiges(): - s = zerlege("\nverwaist\n\n- auch\n") +def test_regeln_vor_erster_funktion_gehoeren_zur_karte(): + s = zerlege("\n- karte\n\nX\n\n- funktion\n") + assert s["regeln"] == "- karte" + assert s["funktionen"][0]["regeln"] == "- funktion" + + +def test_testen_ohne_funktion_landet_in_sonstiges(): + s = zerlege("\n- verwaist\n") assert s["funktionen"] == [] - assert s["sonstiges"] == "verwaist\n\n- auch" + assert s["sonstiges"] == "- verwaist" def test_doppelter_marker_wird_konkateniert(): @@ -72,7 +94,7 @@ def test_doppelter_marker_wird_konkateniert(): def test_leerer_text(): s = zerlege("") - assert s == {"titel": "", "art": "kern", "ziel": "", "funktionen": [], "sonstiges": ""} + assert s == {"titel": "", "art": "kern", "ziel": "", "regeln": "", "funktionen": [], "sonstiges": ""} def test_art_optional(): diff --git a/daten/Planer/darkmode.md b/daten/Planer/darkmode.md index d26c3c2..ae7c9ad 100644 --- a/daten/Planer/darkmode.md +++ b/daten/Planer/darkmode.md @@ -9,11 +9,9 @@ optional ---------------------------------------- Darkmode umschalten - -Icon: ☾ / ☀ - -Folgt beim ersten Start der System-Einstellung - -Zustand bleibt gespeichert - + +- Icon: ☾ / ☀ +- Folgt beim ersten Start der System-Einstellung +- Zustand bleibt gespeichert + - Klick auf Icon in der Sidebar oben diff --git a/daten/Planer/features.md b/daten/Planer/features.md index 84a5df7..3ff193d 100644 --- a/daten/Planer/features.md +++ b/daten/Planer/features.md @@ -5,74 +5,85 @@ Features kern ---------------------------------------- - +Gruppieren Informationen zu ähnlichen Funktionen +---------------------------------------- + +- Alphabetisch sortiert +- Unter daten/ als md Datei gespeichert +- Verlassen speichert +- Escape verwirft ---------------------------------------- -Ausführliche Ansicht umschalten - -Volle Breite - -Funktionen als Boxen in zwei Spalten - -Alle Details offen - +Anzeigemodus umschalten + +Kompaktmodus zum lesen und Vollmodus zum vertiefen und anpassen + +- Standard ist Kompaktmodus +- Vollmodus geht über responsive Spalten +- Vollmodus zeigt alles +- Kompaktmodus zeigt Ziel und Funktionstitel als Liste + +- Klick auf Karte +- Vollmodus sichtbar - Klick auf freie Kartenfläche -- Nochmal klicken schaltet zurück +- Kompaktmodus sichtbar -Feature als Datei speichern - -Projekt = Ordner unter daten/ - -Feature = Markdown-Datei im Projektordner - -Titeländerung benennt die Datei um - -Versionierbar per git +Badge umschalten + +Unterscheidet die Kern- und Optionalen Features + +- Kernfarbe blau +- Optionalfarbe grün +- Verändert die Randfarbe vom Feature + +- Vollmodus öffnen +- Klick auf Badge zum toggeln + +Feature entfernen + +- x-Icon + +- RMB auf Featurecard +- Klick auf "Feature entfernen" +- Bestätigen im Modal +- Feature entfernt Feature erstellen - -Icon: + - -Titel direkt zur Bearbeitung geöffnet - -Karten alphabetisch nach Titel sortiert - -- Klick auf leere Card -- Card wird erstellt + +- +-Icon +- Feature direkt in Vollmodus geöffnet + +- RMB auf Hauptbereich +- Klick auf "Feature erstellen" +- Im Modal Namen eingeben +- Bestätigen -Features entfernen - -Icon: x - -- Hover über Card -- Auf Icon klicken -- Icon wird zum Bestätigungs Icon -- Klick zum entfernen - -Kern/Optional umschalten - -Kern blau umrandet - -Optional grün umrandet - -- Klick auf Badge +Regeln anpassen + +Spezifische Hinweise für Features + +- Nur paar Wörter je Regel + +- Vollmodus öffnen +- Klick auf Regeln +- Inhalt anpassen Titel anpassen - -Enter schließt ab - -Verlassen speichert - -Escape verwirft - -- Hover über Card + +- 1-2 Wörter +- Aktualisiert den Dateinamen + +- Vollmodus öffnen - Klick auf Titel - Inhalt ändern Ziel anpassen - -Leer: Platzhalter „Ziel ergänzen" klicken - -- Hover über Card -- Klick auf Zieltext + +Beschreibt kurz das Kernziel vom Feature + +- 1-2 simple Sätze +- Nur wenn der Titel nicht selbsterklärend ist + +- Vollmodus öffnen +- Klick auf Ziel - Inhalt anpassen diff --git a/daten/Planer/funktionen.md b/daten/Planer/funktionen.md index 6cd4bfe..6c2f69c 100644 --- a/daten/Planer/funktionen.md +++ b/daten/Planer/funktionen.md @@ -8,52 +8,46 @@ kern ---------------------------------------- -Flow anpassen - -Ein Flow je Funktion - -Leeren entfernt den Flow - -- Hover über Funktion -- Klick auf Flow oder + Flow +Testen anpassen + +- Ein Testen-Block je Funktion +- Leeren entfernt den Block + +- Klick auf Testen oder + Testen - Inhalt anpassen Funktion anpassen - + - Klick auf Text - Inhalt ändern Funktion entfernen - -Feld leeren entfernt auch - + +- Feld leeren entfernt auch + - Hover über Funktion - Klick auf x Funktion hinzufügen - -Alphabetisch sortiert - -Neue Funktion rückt nach dem Speichern an ihre Position - -- Hover über Card + +- Alphabetisch sortiert +- Neue Funktion rückt nach dem Speichern an ihre Position + - Klick auf + Funktion - Inhalt eingeben -Regel anpassen - -- Klick auf Text -- Inhalt ändern +Ziel anpassen + +- Ein Ziel je Funktion +- Leeren entfernt das Ziel + +- Klick auf Ziel oder + Ziel +- Inhalt anpassen -Regel entfernen - -Feld leeren entfernt auch - -- Hover über Regel -- Klick auf x - -Regel hinzufügen - -- Hover über Funktion -- Klick auf + Regel -- Inhalt eingeben +Regeln anpassen + +- Eine Regel je Zeile +- Leeren entfernt alle Regeln + +- Klick auf Regeln oder + Regeln +- Inhalt anpassen diff --git a/daten/Planer/projekte.md b/daten/Planer/projekte.md index f9288a8..144ca1f 100644 --- a/daten/Planer/projekte.md +++ b/daten/Planer/projekte.md @@ -5,43 +5,45 @@ Projekte kern ---------------------------------------- - +Gruppiert Features für ein Projekt +---------------------------------------- + +- Alphabetisch sortiert +- Aktives Projekt ist hervorgehoben +- 1-2 Wörter für den Namen ---------------------------------------- Projekt anpassen - -Icon: Stift - -Enter bestätigt - -Escape bricht ab - -- Hover über Projektname -- Klick auf Icon + +- Stift-Icon + +- RMB auf Projektname +- Klick auf "Projekt anpassen" - Inhalt anpassen +- Rausklicken +- Name ist angepasst -Projekt auswählen - -Aktives Projekt ist hervorgehoben - -- Klick auf Name -- Features werden im Hauptbereich angezeigt +Projekt aufrufen + +- LMB auf Projektname +- Features werden angezeigt Projekt entfernen - -Icon: x - -- Hover über Name -- Klick auf Icon -- Icon wird zum Bestätigungs Icon -- Klick zum entfernen + +- X-Icon +- Auch Features entfernen + +- RMB auf Projektname +- Klick auf "Projekt entfernen" +- Bestätigen im Modal +- Projekt entfernt Projekt erstellen - -Alphabetisch in der Sidebar sortiert - -Feature-Anzahl neben dem Namen - -- Inputfeld titel eingeben -- Mit Icon oder Enter erstellen -- Projekt wird direkt ausgewählt + +- Projekt wird direkt aufgerufen +- +-Icon + +- RMB auf Sidebar +- Klick auf "Projekt erstellen" +- Im Modal Namen eingeben +- Bestätigen diff --git a/frontend/src/App.vue b/frontend/src/App.vue index a9c6a06..8cce99d 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,5 +1,5 @@