Setzt Issue #7 um und schliesst damit die Workspace-Map ab. Die files-bar
zeigt nicht mehr zwei Platzhalter-Routen, sondern den rekursiv eingelesenen
Inhalt des offenen Workspace.
TreeNode ist ein verschachteltes Enum mit einer einzigen File-Variante fuer
alle Dateitypen - wer wissen will, ob es eine Notiz ist, fragt
path.extension(). Aufgebaut wird ueber std::fs::read_dir mit eigener
Rekursion; walkdir liegt zwar im Graph, iteriert aber flach, woraus einen
Baum zu bauen mehr Code waere.
Eingesammelt wird alles ausser Namen mit fuehrendem Punkt - Dateien wie
Ordner, womit .dionotes und .git ohne Ausnahmeliste wegfallen - und ausser
Symlinks, deren Verfolgung einen Zyklusschutz erfordern wuerde. Leere Ordner
werden angezeigt, sortiert wird Ordner-vor-Dateien und alphabetisch ohne
Ruecksicht auf Gross-/Kleinschreibung.
Der Aufklapp-Zustand liegt als HashSet<PathBuf> neben dem Baum, nicht darin:
Es gibt keinen Filewatcher, der Nutzer liest bei Bedarf neu ein - steckte
expanded im Knoten, klappte jeder Refresh saemtliche Ordner zu. Persistiert
wird er nicht.
Mit dem Baum entfaellt die Tab-Leiste im Editor und damit EDITOR_TABS, der
letzte Rest des in #5 dokumentierten Pflegepunkts. strum wird dadurch
nirgends mehr gebraucht und faellt samt strum_macros aus dem Graph.
Ausserdem entfernt: der Dioxus-Vorlagentext Hero samt header.svg, der nach
dem Oeffnen eines Workspace die rechte Haelfte mit ungestylten Werbelinks
fuellte. Home ist jetzt ein Empty-State.
Setzt Issue #8 um: eine Ansicht statt Reiter. Die Liste der bekannten
Workspaces fuehrt, das Hinzufuegen sitzt als Nebenaktion in der Fusszeile und
wird nur beim leeren Erststart zur Primaeraktion. Oeffnen ist der
Alltagsfall, Hinzufuegen passiert pro Workspace genau einmal - zwei
gleichrangige Reiter haetten bei jedem Start eine Entscheidung verlangt, die
fast immer dieselbe ist.
Ein Eintrag zeigt den Ordnernamen, darunter den Pfad in der Code-Schrift. Der
Pfad wird bei Ueberlaenge vorne gekuerzt, weil sein Ende mehr aussagt als sein
Anfang.
Die Zustandspruefung laeuft nebenlaeufig ueber use_resource und
spawn_blocking. Ohne das wuerde ein nicht eingehaengtes Netzlaufwerk den
Selector einfrieren: dort laeuft schon is_dir() in ein Timeout von Sekunden,
und zwar auf dem Bildschirm, den jeder Start zuerst zeigt. Solange die
Pruefung laeuft, bleiben die Eintraege unmarkiert.
Die drei Zustaende aus #6 bekommen eigene Farben und Formulierungen - nicht
erreichbar, kein Workspace mehr, beschaedigt -, weil sie zu verschiedenen
Handlungen fuehren. Ein defekter Eintrag wird gedaempft, bleibt aber
anklickbar und verschwindet nie automatisch: Meist fehlt nur gerade das
Laufwerk, und ein Klick versucht es erneut.
OpenError ist dafuer Clone und PartialEq geworden; Io traegt jetzt die
Meldung als String statt io::Error, der beides nicht kann.
Setzt die Entscheidungen aus #2, #4 und #6 um: Der Knopf "Workspace
hinzufuegen..." oeffnet den nativen Ordner-Dialog, legt den Marker an und
uebernimmt den Workspace in Context, Liste und Editor.
Der Marker ist .dionotes/workspace.ron mit genau (schema_version: 1). Er wird
additiv angelegt, vorhandene Dateien bleiben unberuehrt - ein Test haelt das
fest. Ein beschaedigter Marker fuehrt dazu, dass der Workspace nicht
geoeffnet und der Marker nicht neu geschrieben wird; auch das ist getestet,
denn sobald dort ein Passwort-Hash liegt, waere stillschweigendes Neuanlegen
ein Weg, den Schutz auszuhebeln.
OpenError unterscheidet die drei Zustaende aus #6 - nicht erreichbar, kein
Workspace mehr, beschaedigt - plus den Fall eines zu neuen Schemas. Die
Display-Impl liefert genau die Formulierungen, mit denen spaeter die
Listeneintraege markiert werden.
Der Flow folgt der Regel aus #6: Ein abgebrochener Dialog ist kein Fehler und
erzeugt keine Meldung. Ein Ordner, der bereits Workspace ist, wird geoeffnet
statt abgelehnt - derselbe Knopf nimmt neue und wiedergefundene Workspaces
auf, was seine Beschriftung erst rechtfertigt. Ein nicht leerer Ordner loest
eine Rueckfrage aus, die ausdruecklich sagt, dass nichts Vorhandenes
veraendert wird; das ist beim Import der Normalfall, keine Ausnahme.
rfd wird mit denselben Features eingebunden, die dioxus-desktop ohnehin zieht
(xdg-portal statt default). Mit den Default-Features waeren neun
Wayland-Pakete dazugekommen, die das Portal nicht braucht - so kostet die
explizite Abhaengigkeit keinen einzigen zusaetzlichen Eintrag.
Die App hat nie eine Tailwind-Utility benutzt - saemtliche Klassen im Code
sind eigene (btn, files-bar, empty-state, ...), und den Reset liefert
base.css selbst. Damit standen package.json, node_modules und ein
Build-Schritt fuer eine Stylesheet-Datei, die nichts beigetragen hat.
Aufgefallen ist es, weil der letzte Commit ungefragt zwoelf Zeilen in
assets/tailwind.css mitbrachte: Der Generator scannt auch docs/ und erzeugte
Utilities fuer Woerter, die er in Prosa fand.
Die npm-Abhaengigkeit war ohnehin wirkungslos - Dioxus 0.7 bringt Tailwind
selbst mit (erzeugt wurde 4.1.5, nicht die in package.json deklarierte 4.3.3).
Ohne die Eingabedatei tailwind.css im Projektwurzelverzeichnis erzeugt dx
nichts mehr; verifiziert durch einen vollstaendigen Build.
Das --dn-Praefix der Tokens bleibt: Es war urspruenglich Schutz vor Tailwinds
eigenen :root-Variablen, taugt aber weiterhin als Namensraum.
README auf den tatsaechlichen Projektstand gebracht - er beschrieb noch die
Dioxus-Vorlage mit einer einzelnen main.rs.
Die App hatte zwei Routable-Enums, zwischen denen ein Signal<bool> umschaltete.
Der Schalter wurde nie gesetzt - beim ersten Umlegen waere aufgefallen, dass
sich beide Router dieselbe History teilen und beide "/" belegen: Wer im
Selector auf "Open Workspace" klickt, steht auf /ws_open, und der
Editor-Router kennt nur / und /editor.
Jetzt ein Enum, der Editor-Teil unter #[nest("/workspace")]. An die Stelle des
bool tritt Signal<Option<Workspace>> in einem Context-Provider - Props
scheiden aus, weil sich durch ein Outlet keine durchreichen lassen. Fehlt der
Workspace, schickt ein Guard im EditorShell-Layout zurueck zum Selector; der
Fall tritt real bei Hot-Reload auf, wo der Context faellt und die Route bleibt.
Der Selector verliert seine Reiter und wird eine einzige Route. Das folgt aus
dem UI-Prototyp in Issue #8: Oeffnen ist der Alltagsfall, Hinzufuegen passiert
pro Workspace einmal - zwei gleichrangige Reiter verlangten bei jedem Start
eine Entscheidung, die fast immer dieselbe ist. Damit entfallen der leere
Stub create_new_workspace.rs, die Tab-Konstante fuer den Selector und die
zugehoerigen CSS-Klassen.
Weil EnumIter nicht mehr gebraucht wird, faellt strum_macros als direkte
Abhaengigkeit weg; strum re-exportiert die Derives bereits.
Entscheidungen dazu in den Issues #5, #6 und #8.
Cargo-, Dioxus- und Tailwind-Konfiguration, Clippy-Regeln, Assets und
Stylesheets (tokens/base/layout/components). Cargo.lock wird eingecheckt,
da es sich um ein Binary-Crate handelt.
node_modules/ und .idea/ per .gitignore ausgeschlossen.