]> danix's work - publisher.git/commitdiff
feat: articles view with IT/EN tabs and missing translation highlight
authorDanilo M. <redacted>
Sun, 3 May 2026 08:32:47 +0000 (10:32 +0200)
committerDanilo M. <redacted>
Sun, 3 May 2026 08:32:47 +0000 (10:32 +0200)
ui/articles_view.py [new file with mode: 0644]
ui/main_window.py

diff --git a/ui/articles_view.py b/ui/articles_view.py
new file mode 100644 (file)
index 0000000..d3fac93
--- /dev/null
@@ -0,0 +1,82 @@
+from __future__ import annotations
+from PyQt6.QtWidgets import (
+    QWidget, QVBoxLayout, QHBoxLayout, QTabWidget,
+    QListWidget, QListWidgetItem, QLabel, QPushButton,
+)
+from PyQt6.QtCore import Qt, pyqtSignal
+from PyQt6.QtGui import QColor
+from core.models import Article
+
+class ArticleItem(QListWidgetItem):
+    def __init__(self, article: Article):
+        super().__init__()
+        self.article = article
+        lang_other = "EN" if article.lang == "it" else "IT"
+        if article.has_translation:
+            badge = f"🇬🇧 ✓" if article.lang == "it" else "🇮🇹 ✓"
+            status = f"{article.slug}  [{badge}]"
+        else:
+            badge = f"🇬🇧 ✗" if article.lang == "it" else "🇮🇹 ✗"
+            status = f"{article.slug}  [{badge}]"
+        self.setText(status)
+        if not article.has_translation:
+            self.setForeground(QColor("#ff6b6b"))
+
+class ArticlesView(QWidget):
+    article_selected = pyqtSignal(object)  # Article
+    translate_requested = pyqtSignal(object)  # Article
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self._articles: list[Article] = []
+        self._build_ui()
+
+    def _build_ui(self):
+        layout = QVBoxLayout(self)
+        layout.setContentsMargins(0, 0, 0, 0)
+        self._tabs = QTabWidget()
+        self._tabs.setStyleSheet("QTabBar::tab { padding: 6px 16px; }")
+        self._list_it = QListWidget()
+        self._list_en = QListWidget()
+        self._tabs.addTab(self._list_it, "🇮🇹 Italiano")
+        self._tabs.addTab(self._list_en, "🇬🇧 English")
+        layout.addWidget(self._tabs)
+        self._list_it.itemClicked.connect(lambda item: self.article_selected.emit(item.article))
+        self._list_en.itemClicked.connect(lambda item: self.article_selected.emit(item.article))
+
+    def set_articles(self, articles: list[Article]):
+        self._articles = articles
+        self._list_it.clear()
+        self._list_en.clear()
+        for a in articles:
+            item = ArticleItem(a)
+            if a.lang == "it":
+                self._list_it.addItem(item)
+            else:
+                self._list_en.addItem(item)
+
+class MissingTranslationView(QWidget):
+    article_selected = pyqtSignal(object)  # Article
+    translate_requested = pyqtSignal(object)  # Article
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self._build_ui()
+
+    def _build_ui(self):
+        layout = QVBoxLayout(self)
+        header = QLabel("⚠️ Articoli senza traduzione")
+        header.setStyleSheet("color: #ff6b6b; font-weight: bold; font-size: 13px; padding: 10px;")
+        layout.addWidget(header)
+        self._list = QListWidget()
+        layout.addWidget(self._list)
+        self._list.itemClicked.connect(lambda item: self.article_selected.emit(item.article))
+
+    def set_articles(self, articles: list[Article]):
+        self._list.clear()
+        missing = [a for a in articles if not a.has_translation]
+        for a in missing:
+            lang_other = "🇬🇧" if a.lang == "it" else "🇮🇹"
+            item = ArticleItem(a)
+            item.setText(f"{a.slug}  [manca {lang_other}]  ({a.lang.upper()})")
+            self._list.addItem(item)
index cbefa5f2d006f9a9925346052b9d65984064152c..01e4cf2e2d6af66f7ed62f2d4f282ba89e867301 100644 (file)
@@ -1,4 +1,5 @@
 from __future__ import annotations
+import subprocess
 from PyQt6.QtWidgets import (
     QMainWindow, QWidget, QHBoxLayout, QVBoxLayout,
     QLabel, QPushButton, QStackedWidget, QFrame,
@@ -54,9 +55,32 @@ class MainWindow(QMainWindow):
         self._stack = QStackedWidget()
         root.addWidget(self._stack, stretch=1)
 
-        # Placeholder pages (replaced in later tasks)
-        for name in ["articles", "no_translation", "new_article", "taxonomy",
-                     "media", "translations", "git", "hugo"]:
+        from ui.articles_view import ArticlesView, MissingTranslationView
+
+        self._articles_view = ArticlesView()
+        self._articles_view.article_selected.connect(self._on_article_selected)
+        self._stack.addWidget(self._articles_view)
+        self._page_articles = self._stack.count() - 1
+
+        self._missing_view = MissingTranslationView()
+        self._missing_view.article_selected.connect(self._on_article_selected)
+        self._stack.addWidget(self._missing_view)
+        self._page_no_translation = self._stack.count() - 1
+
+        from ui.article_detail import ArticleDetailView
+
+        self._detail_view = ArticleDetailView()
+        self._detail_view.open_typora.connect(self._do_open_typora)
+        self._detail_view.open_frontmatter.connect(self._do_open_frontmatter)
+        self._detail_view.translate.connect(self._do_translate)
+        self._detail_view.push_master.connect(lambda a: self._do_git_push("master"))
+        self._detail_view.publish.connect(lambda a: self._do_git_push("production"))
+        self._detail_view.delete_article.connect(self._do_delete_article)
+        self._stack.addWidget(self._detail_view)
+        self._page_detail = self._stack.count() - 1
+
+        # Remaining placeholders
+        for name in ["new_article", "taxonomy", "media", "translations", "git", "hugo"]:
             w = QLabel(f"[{name}]")
             w.setAlignment(Qt.AlignmentFlag.AlignCenter)
             self._stack.addWidget(w)
@@ -136,9 +160,33 @@ class MainWindow(QMainWindow):
         if not self.config.blog_repo:
             return
         self._articles = scan_articles(Path(self.config.blog_repo))
+        self._articles_view.set_articles(self._articles)
+        self._missing_view.set_articles(self._articles)
         missing = [a for a in self._articles if not a.has_translation]
         self._badge_no_trans.setText(str(len(missing)))
 
+    def _on_article_selected(self, article: Article):
+        self._detail_view.set_article(article)
+        self._stack.setCurrentIndex(self._page_detail)
+
+    def _do_open_typora(self, article: Article):
+        subprocess.Popen([self.config.typora_bin, str(article.path)])
+
+    def _do_open_frontmatter(self, article: Article):
+        from ui.frontmatter_editor import FrontmatterEditor
+        dlg = FrontmatterEditor(article, Path(self.config.blog_repo), self)
+        if dlg.exec():
+            self._detail_view.set_article(article)
+
+    def _do_translate(self, article: Article):
+        pass  # implemented in Task 15
+
+    def _do_git_push(self, branch: str):
+        pass  # implemented in Task 16
+
+    def _do_delete_article(self, article: Article):
+        pass  # implemented in Task 16
+
     def _setup_watcher(self):
         if not self.config.blog_repo:
             return