Refinement-Runde Panel/Wiki: Bedienung, Themes, Archiv-Wahl, Frontend-Tests
- Slug transliteriert Umlaute/ß (fuer statt f-r); aktiver Tab mit Akzent + Unterstrich; kein aktiver Tab bei zugeklapptem Panel (mode.clear) - Suche: Live-Update auch beim Löschen (<3 Zeichen: Hinweis), #tag-Filter in der Query, Treffer öffnen im Dokument-Tab (panel_load, ohne Frontmatter); Wiki-Sprung-Button im Dokument; Wiki-Fehler sichtbar als Toast - Archiv-Formular am Archiv-Button (Ordner/Beschreibung/Schlagwörter); panel_archive_cmd nimmt Meta entgegen - Wiki-Übersicht: Zuletzt-Sektion, Backlink-Zähler, Wurzel-Eyebrow - Themes: Panel-Farben über CSS-Variablen, applyTheme leitet sie aus dem jeweiligen Theme ab (auch helle); gemeinsames themes.ts - Fenster: Doppelklick maximiert; gelöstes Fenster merkt Größe/Position (Window-ACL: set-position/outer-position/inner-size ergänzt); open_panel_window async (GTK-Deadlock-Vorgabe); Panel-Fenster spiegelt JS-Fehler ins Dev-Log - Archiv pro Projekt wähl-/abwählbar (Einstellungsdialog, setzt/entfernt Permissions); require_archive_home legt den Ordner an; ohne Archiv nur Befehle+Dokument im Panel - Frontend-Tests: vitest + happy-dom, 27 Tests über Modus-, Such-, Wiki-, Editor- und Formular-Logik (npm test)
This commit is contained in:
+37
-22
@@ -11,8 +11,9 @@ import { invoke } from "@tauri-apps/api/core";
|
||||
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { wirePanel } from "./panel-wiring";
|
||||
import { THEMES } from "./themes";
|
||||
import { applyTheme, THEMES } from "./themes";
|
||||
import { flash, panelToast } from "./commands-view";
|
||||
import { initArchiveForm } from "./archive-form";
|
||||
|
||||
// Debug-Instrumentierung: Fehler auf der Seite anzeigen und ins Dev-Log spiegeln.
|
||||
function showError(msg: string) {
|
||||
@@ -56,6 +57,13 @@ if (!isMac) {
|
||||
}
|
||||
}
|
||||
|
||||
// Doppelklick auf die Kopfleiste maximiert (Fenster-Konvention).
|
||||
document.querySelector("header")!.addEventListener("dblclick", (e) => {
|
||||
if ((e.target as HTMLElement).hasAttribute("data-tauri-drag-region")) {
|
||||
win.toggleMaximize();
|
||||
}
|
||||
});
|
||||
|
||||
// Fensterhintergrund beim Öffnen kommt aus terminal.rs (theme_background);
|
||||
// dort nicht gepflegte Themes fallen auf Mocha zurück (nur kurzer Moment
|
||||
// bis die Webview lädt).
|
||||
@@ -90,14 +98,8 @@ if (cfg?.terminal.icon) {
|
||||
const picked = THEMES[cfg?.terminal.theme ?? "mocha"];
|
||||
const theme = picked.xterm;
|
||||
|
||||
// Seitenfarben ans Theme anpassen (Defaults in terminal.html sind Mocha).
|
||||
document.documentElement.style.background = theme.background;
|
||||
document.body.style.background = theme.background;
|
||||
document.body.style.borderColor = picked.border;
|
||||
const header = document.querySelector("header") as HTMLElement;
|
||||
header.style.background = picked.header;
|
||||
header.style.borderBottomColor = picked.border;
|
||||
header.style.color = theme.foreground;
|
||||
// Seitenfarben ans Theme anpassen — alles Weitere hängt an den CSS-Variablen.
|
||||
applyTheme(picked);
|
||||
|
||||
// Globale Schriftgröße (settings.json: terminalFontSize), ein Wert für alle.
|
||||
const DEFAULT_FONT_SIZE = 13;
|
||||
@@ -186,13 +188,6 @@ term.focus();
|
||||
const panel = document.getElementById("panel")!;
|
||||
const splitter = document.getElementById("splitter")!;
|
||||
|
||||
// Panelfarben ans Theme koppeln.
|
||||
panel.style.background = picked.header;
|
||||
panel.style.color = theme.foreground;
|
||||
splitter.style.background = picked.border;
|
||||
(panel.querySelector(".panel-head") as HTMLElement).style.borderBottomColor =
|
||||
picked.border;
|
||||
|
||||
let detached = false;
|
||||
let hasContent = false;
|
||||
|
||||
@@ -209,39 +204,52 @@ function hidePanel() {
|
||||
|
||||
// Gemeinsame Verdrahtung (Views, Modi, Update-Events); jedes eingehende
|
||||
// Update blendet das angedockte Panel ein, solange es nicht abgelöst ist.
|
||||
const { view } = await wirePanel(project, () => {
|
||||
const { view, mode } = await wirePanel(project, () => {
|
||||
hasContent = true;
|
||||
if (!detached) showPanel();
|
||||
});
|
||||
// Panel startet zugeklappt — kein Tab aktiv, bis eine Ansicht geöffnet wird.
|
||||
mode.clear();
|
||||
|
||||
// Tab-Klick im Header öffnet das (angedockte) Panel, falls es zu ist.
|
||||
document.getElementById("panel-tabs")!.addEventListener("click", () => {
|
||||
const headerTabs = document.getElementById("panel-tabs")!;
|
||||
headerTabs.addEventListener("click", () => {
|
||||
hasContent = true;
|
||||
if (!detached) showPanel();
|
||||
});
|
||||
|
||||
// Solange das Panel abgelöst ist, hat das eigene Fenster die Tabs — die im
|
||||
// Header verschwinden.
|
||||
await listen("panel-detached", () => {
|
||||
detached = true;
|
||||
headerTabs.hidden = true;
|
||||
hidePanel();
|
||||
mode.clear();
|
||||
});
|
||||
await listen("panel-attached", () => {
|
||||
detached = false;
|
||||
headerTabs.hidden = false;
|
||||
if (hasContent) showPanel();
|
||||
});
|
||||
// Abgelöstes Fenster geschlossen (per ✕ oder OS): angedocktes Panel bleibt
|
||||
// ausgeblendet, aber der nächste Entwurf darf es wieder einblenden.
|
||||
await listen("panel-window-closed", () => {
|
||||
detached = false;
|
||||
headerTabs.hidden = false;
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById("panel-detach")!
|
||||
.addEventListener("click", () => invoke("open_panel_window", { project }));
|
||||
document.getElementById("panel-hide")!.addEventListener("click", hidePanel);
|
||||
document.getElementById("panel-hide")!.addEventListener("click", () => {
|
||||
hidePanel();
|
||||
mode.clear();
|
||||
});
|
||||
|
||||
// Archivieren: konfigurierten Ordner nehmen, sonst per Dialog wählen (setzt ihn).
|
||||
// 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")!;
|
||||
archiveBtn.addEventListener("click", async () => {
|
||||
const archiveForm = initArchiveForm(archiveBtn, async (meta) => {
|
||||
try {
|
||||
const configured = await invoke<string | null>("panel_archive_dir_cmd", {
|
||||
project,
|
||||
@@ -254,7 +262,13 @@ archiveBtn.addEventListener("click", async () => {
|
||||
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 });
|
||||
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) {
|
||||
@@ -263,6 +277,7 @@ archiveBtn.addEventListener("click", async () => {
|
||||
invoke("term_log", { msg: `archive: ${e}` });
|
||||
}
|
||||
});
|
||||
archiveBtn.addEventListener("click", () => archiveForm.toggle());
|
||||
|
||||
// Splitter: Panelbreite ziehen.
|
||||
splitter.addEventListener("mousedown", (e) => {
|
||||
|
||||
Reference in New Issue
Block a user