]> danix's work - publisher.git/commitdiff
feat: frontmatter editor dialog with type dropdown and tag autocomplete
authorDanilo M. <redacted>
Sun, 3 May 2026 08:33:08 +0000 (10:33 +0200)
committerDanilo M. <redacted>
Sun, 3 May 2026 08:33:08 +0000 (10:33 +0200)
ui/frontmatter_editor.py [new file with mode: 0644]

diff --git a/ui/frontmatter_editor.py b/ui/frontmatter_editor.py
new file mode 100644 (file)
index 0000000..218bbac
--- /dev/null
@@ -0,0 +1,85 @@
+from __future__ import annotations
+from PyQt6.QtWidgets import (
+    QDialog, QVBoxLayout, QHBoxLayout, QFormLayout,
+    QLabel, QLineEdit, QComboBox, QPushButton,
+    QCompleter, QWidget, QScrollArea,
+)
+from PyQt6.QtCore import Qt
+from pathlib import Path
+from core.models import Article, ARTICLE_TYPES
+from core.frontmatter import parse_frontmatter, write_frontmatter
+from core.taxonomy import load_taxonomy
+
+class FrontmatterEditor(QDialog):
+    def __init__(self, article: Article, blog_root: Path, parent=None):
+        super().__init__(parent)
+        self.setWindowTitle(f"Frontmatter — {article.slug}")
+        self.setMinimumWidth(520)
+        self._article = article
+        self._blog_root = blog_root
+        self._fields: dict[str, QWidget] = {}
+        self._build_ui()
+
+    def _build_ui(self):
+        layout = QVBoxLayout(self)
+
+        scroll = QScrollArea()
+        scroll.setWidgetResizable(True)
+        inner = QWidget()
+        form = QFormLayout(inner)
+        scroll.setWidget(inner)
+        layout.addWidget(scroll)
+
+        lang = self._article.lang
+        tags_it = self._blog_root / "docs" / "tags-it.txt"
+        tags_en = self._blog_root / "docs" / "tags-en.txt"
+        taxonomy = load_taxonomy(tags_it, tags_en)
+        known_tags = list(taxonomy.it_to_en.keys()) if lang == "it" else list(taxonomy.it_to_en.values())
+
+        for key, val in self._article.frontmatter.items():
+            if key == "type":
+                widget = QComboBox()
+                widget.addItems(ARTICLE_TYPES)
+                if str(val) in ARTICLE_TYPES:
+                    widget.setCurrentText(str(val))
+                self._fields[key] = widget
+            elif key == "tags":
+                widget = QLineEdit(", ".join(str(v) for v in val) if isinstance(val, list) else str(val))
+                completer = QCompleter(known_tags)
+                completer.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
+                widget.setCompleter(completer)
+                self._fields[key] = widget
+            else:
+                widget = QLineEdit(str(val))
+                self._fields[key] = widget
+            form.addRow(QLabel(key), widget)
+
+        btns = QHBoxLayout()
+        save_btn = QPushButton("Salva")
+        save_btn.clicked.connect(self._save)
+        cancel_btn = QPushButton("Annulla")
+        cancel_btn.clicked.connect(self.reject)
+        btns.addStretch()
+        btns.addWidget(cancel_btn)
+        btns.addWidget(save_btn)
+        layout.addLayout(btns)
+
+    def _save(self):
+        updated = dict(self._article.frontmatter)
+        for key, widget in self._fields.items():
+            if isinstance(widget, QComboBox):
+                updated[key] = widget.currentText()
+            elif isinstance(widget, QLineEdit):
+                val = widget.text().strip()
+                if key == "tags":
+                    updated[key] = [t.strip() for t in val.split(",") if t.strip()]
+                else:
+                    updated[key] = val
+        try:
+            _, body = parse_frontmatter(self._article.path)
+            write_frontmatter(self._article.path, updated, body)
+            self._article.frontmatter.update(updated)
+            self.accept()
+        except Exception as e:
+            from PyQt6.QtWidgets import QMessageBox
+            QMessageBox.critical(self, "Errore", str(e))