Archiv als eigenes Fenster: Trilium raus, Notizbaum mit In-Place-Bearbeitung
Trilium-Integration komplett zurückgenommen (Revert von 47951a6): keine
verwaltete Instanz, kein Runtime-Download, kein ETAPI, kein Keyring-Token,
kein Setup-Wizard. Das Archiv sind wieder Markdown-Dateien unter archiveHome
samt FTS5-Suche und Wikilinks.
Notizmodell (an Trilium orientiert, ohne dessen Überbau):
- Jeder Knoten besitzt eine Textdatei — ensure_node_texts legt fehlende beim
Seitenaufbau an (Ordner: gleichnamiges .md daneben, Wurzel: index.md);
Ordner und Zwillingsdatei sind EINE Notiz mit Inhalt und Kindern.
- Der angezeigte Titel steht im Frontmatter der Datei, der Datei-/Ordnername
ist technischer Verwaltungsname; move_folder nimmt den Knotentext mit.
Archiv-Ansicht (wiki-view):
- Baum links: Knoten- und Blatt-Symbole, Führungslinien pro Ebene, Dokumente
näher an der Linie als Ordner; ganze Zeile wählt aus, nur der Pfeil klappt.
- Notiz-Ansicht rechts: großer Titel (Klick bearbeitet ihn → archive_set_title),
Zurück-Knopf mit Auswahl-Verlauf, Details als Popup am Info-Knopf, Kindliste
als abgesetzter Karten-Block mit Anlage-/Änderungsdatum.
- Bearbeiten in place: Split-View aus Rohtext und Live-Vorschau, Speichern per
Knopf oder Ctrl+S (archive_read/archive_write; Frontmatter bleibt).
- Rechte Maustaste im Baum als einziger Aktionsweg (eigenes Kontextmenü,
Standard-Menü des Webviews aus); Anlegen/Umbenennen über modale Dialoge.
Feste Flächenaufteilung statt Ablösen/Andocken:
- Angedocktes Panel = Session-Begleiter (ToDo, Befehle, flüchtiger Entwurf);
der Dokument-Tab ist aus der Leiste raus.
- Archiv-Fenster = Archiv + Suche, Größe und Position einmalig beim Öffnen
aus dem Monitor des rufenden Terminal-Fensters (85 % / 92 %); Öffner-Klick
bei stehendem Fenster fokussiert und schaltet den Tab (panel-mode).
- Terminal-Fenster zu → Archiv-Fenster geht mit.
Neue Commands: archive_read, archive_write, archive_set_title.
This commit is contained in:
+59
-22
@@ -15,7 +15,8 @@ import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { wirePanel } from "./panel-wiring";
|
||||
import { applyTheme, THEMES } from "./themes";
|
||||
import { panelToast } from "./tiles";
|
||||
import { flash, panelToast } from "./tiles";
|
||||
import { initArchiveForm } from "./archive-form";
|
||||
import { applyI18n, t } from "./messages";
|
||||
|
||||
// Debug-Instrumentierung: Fehler auf der Seite anzeigen und ins Dev-Log spiegeln.
|
||||
@@ -188,10 +189,10 @@ window.addEventListener("resize", () => fit.fit());
|
||||
await invoke("term_start", { project, rows: term.rows, cols: term.cols });
|
||||
term.focus();
|
||||
|
||||
// --- Andockbares Panel ----------------------------------------------------
|
||||
// Die MCP-Tools schreiben in die Puffer-Dateien; terminal.rs meldet neuen
|
||||
// Inhalt als `<buffer>-update`. Das Panel blendet sich dann ein — außer es
|
||||
// ist gerade in ein eigenes Fenster abgelöst (`panel-detached`).
|
||||
// --- Andockbares Entwurfs-Panel -------------------------------------------
|
||||
// Der Skill schreibt Entwürfe in eine Datei; terminal.rs meldet neuen Inhalt
|
||||
// per `panel-update`. Das Panel blendet sich dann ein — außer es ist gerade in
|
||||
// ein eigenes Fenster abgelöst (`panel-detached`).
|
||||
const panel = document.getElementById("panel")!;
|
||||
const splitter = document.getElementById("splitter")!;
|
||||
|
||||
@@ -211,20 +212,10 @@ function hidePanel() {
|
||||
|
||||
// Gemeinsame Verdrahtung (Views, Modi, Update-Events); jedes eingehende
|
||||
// Update blendet das angedockte Panel ein, solange es nicht abgelöst ist.
|
||||
const { views, mode } = await wirePanel(project, () => {
|
||||
const { view, views, mode } = await wirePanel(project, () => {
|
||||
hasContent = true;
|
||||
if (!detached) showPanel();
|
||||
});
|
||||
|
||||
// write_panel hat eine Notiz angelegt: das Trilium-Fenster des Projekts
|
||||
// zeigt sie. Leerer Puffer = Session-Start, keine Notiz.
|
||||
await listen<string>("noteopen-update", (e) => {
|
||||
if (!e.payload.trim()) return;
|
||||
const { noteId } = JSON.parse(e.payload);
|
||||
void invoke("trilium_open", { project, noteId }).catch((err) =>
|
||||
panelToast(String(err)),
|
||||
);
|
||||
});
|
||||
// Panel startet zugeklappt — außer das ToDo-Modul ist gewählt und die Liste
|
||||
// nicht leer: dann öffnet das Panel beim Start mit der ToDo-Ansicht.
|
||||
const todos = views.get("todo");
|
||||
@@ -238,6 +229,22 @@ if (todos && !todos.empty()) {
|
||||
|
||||
// Tab-Klick im Header öffnet das (angedockte) Panel, falls es zu ist.
|
||||
const headerTabs = document.getElementById("panel-tabs")!;
|
||||
// Ausnahme Archiv & Suche: öffnen standardmäßig im eigenen Panel-Fenster
|
||||
// (Popup) statt in der schmalen angedockten Spalte — Capture-Phase, damit
|
||||
// weder der Modus-Wechsel des Tabs noch das Einblenden des Panels feuern.
|
||||
headerTabs.addEventListener(
|
||||
"click",
|
||||
(e) => {
|
||||
const btn = (e.target as HTMLElement).closest<HTMLElement>(
|
||||
'button[data-mode="wiki"], button[data-mode="search"]',
|
||||
);
|
||||
if (!btn) return;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
void invoke("open_panel_window", { project, mode: btn.dataset.mode });
|
||||
},
|
||||
{ capture: true },
|
||||
);
|
||||
headerTabs.addEventListener("click", () => {
|
||||
hasContent = true;
|
||||
if (!detached) showPanel();
|
||||
@@ -263,17 +270,47 @@ await listen("panel-window-closed", () => {
|
||||
headerTabs.hidden = false;
|
||||
});
|
||||
|
||||
// Der aktive Tab wandert mit ins abgelöste Fenster.
|
||||
document
|
||||
.getElementById("panel-detach")!
|
||||
.addEventListener("click", () =>
|
||||
invoke("open_panel_window", { project, mode: mode.current() }),
|
||||
);
|
||||
// Ablösen gibt es nicht mehr — die Flächen sind fest verteilt; der Knopf
|
||||
// bleibt versteckt.
|
||||
document.getElementById("panel-detach")!.hidden = true;
|
||||
document.getElementById("panel-hide")!.addEventListener("click", () => {
|
||||
hidePanel();
|
||||
mode.clear();
|
||||
});
|
||||
|
||||
// Archivieren: Button klappt das Formular (Ordner/Beschreibung/Schlagwörter)
|
||||
// auf; Abschicken wählt notfalls erst das Archiv-Home per Dialog.
|
||||
const archiveBtn = document.getElementById("panel-archive")!;
|
||||
const archiveForm = initArchiveForm(archiveBtn, async (meta) => {
|
||||
try {
|
||||
const configured = await invoke<string | null>("panel_archive_dir_cmd", {
|
||||
project,
|
||||
});
|
||||
let dir: string | undefined;
|
||||
if (!configured) {
|
||||
const { open } = await import("@tauri-apps/plugin-dialog");
|
||||
const chosen = await open({ directory: true, title: t("panel.chooseArchiveDir") });
|
||||
if (!chosen) return;
|
||||
dir = chosen as string;
|
||||
}
|
||||
await view.flush(); // offene Bearbeitung erst speichern — archiviert, was zu sehen ist
|
||||
const path = await invoke<string>("panel_archive_cmd", {
|
||||
project,
|
||||
dir,
|
||||
folder: meta.folder ?? null,
|
||||
description: meta.description ?? null,
|
||||
tags: meta.tags,
|
||||
});
|
||||
flash(archiveBtn, "copied", 1400);
|
||||
invoke("reveal_path_cmd", { path });
|
||||
} catch (e) {
|
||||
flash(archiveBtn, "error", 1400);
|
||||
panelToast(`Archivieren fehlgeschlagen: ${e}`);
|
||||
invoke("term_log", { msg: `archive: ${e}` });
|
||||
}
|
||||
});
|
||||
archiveBtn.addEventListener("click", () => archiveForm.toggle());
|
||||
|
||||
// Splitter: Panelbreite ziehen.
|
||||
splitter.addEventListener("mousedown", (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
Reference in New Issue
Block a user