diff options
Diffstat (limited to 'docs/superpowers/plans/2026-05-03-article-list-metadata.md')
| -rw-r--r-- | docs/superpowers/plans/2026-05-03-article-list-metadata.md | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/docs/superpowers/plans/2026-05-03-article-list-metadata.md b/docs/superpowers/plans/2026-05-03-article-list-metadata.md new file mode 100644 index 0000000..a9b97aa --- /dev/null +++ b/docs/superpowers/plans/2026-05-03-article-list-metadata.md @@ -0,0 +1,200 @@ +# Article List Metadata Display Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Show type, tags, categories, and date for each article row in the articles list (both IT and EN tabs). + +**Architecture:** Extend `ArticleItem` to render a two-line item: line 1 = slug + translation badge (existing), line 2 = metadata fields extracted from `article.frontmatter`. Use `\n` in item text and `setSizeHint` for row height. No new files needed. + +**Tech Stack:** PyQt6 QListWidgetItem, existing Article.frontmatter dict. + +--- + +### Task 1: Add metadata helpers to Article model + +**Files:** +- Modify: `core/models.py` +- Test: `tests/test_models.py` + +- [ ] **Step 1: Write failing tests** + +Add to `tests/test_models.py`: + +```python +def test_article_draft_property(): + fm = {"draft": True, "type": "Tech", "tags": ["linux"], "categories": ["DIY"], "date": "2024-01-15T10:00:00+00:00"} + a = Article(slug="test", lang="it", path=Path("/tmp/test"), frontmatter=fm, has_translation=False, translation_path=None) + assert a.draft is True + +def test_article_meta_type(): + fm = {"type": "Tech"} + a = Article(slug="test", lang="it", path=Path("/tmp/test"), frontmatter=fm, has_translation=False, translation_path=None) + assert a.meta_type == "Tech" + +def test_article_meta_type_missing(): + a = Article(slug="test", lang="it", path=Path("/tmp/test"), frontmatter={}, has_translation=False, translation_path=None) + assert a.meta_type == "" + +def test_article_meta_tags(): + fm = {"tags": ["linux", "python"]} + a = Article(slug="test", lang="it", path=Path("/tmp/test"), frontmatter=fm, has_translation=False, translation_path=None) + assert a.meta_tags == "linux, python" + +def test_article_meta_tags_empty(): + a = Article(slug="test", lang="it", path=Path("/tmp/test"), frontmatter={}, has_translation=False, translation_path=None) + assert a.meta_tags == "" + +def test_article_meta_categories(): + fm = {"categories": ["DIY", "Tech"]} + a = Article(slug="test", lang="it", path=Path("/tmp/test"), frontmatter=fm, has_translation=False, translation_path=None) + assert a.meta_categories == "DIY, Tech" + +def test_article_meta_date(): + fm = {"date": "2024-01-15T10:00:00+00:00"} + a = Article(slug="test", lang="it", path=Path("/tmp/test"), frontmatter=fm, has_translation=False, translation_path=None) + assert a.meta_date == "2024-01-15" + +def test_article_meta_date_missing(): + a = Article(slug="test", lang="it", path=Path("/tmp/test"), frontmatter={}, has_translation=False, translation_path=None) + assert a.meta_date == "" +``` + +- [ ] **Step 2: Run tests to confirm they fail** + +```bash +pytest tests/test_models.py -v +``` + +Expected: FAIL — `Article` has no `meta_type`, `meta_tags`, `meta_categories`, `meta_date` attributes. + +- [ ] **Step 3: Implement properties in Article** + +In `core/models.py`, add four properties after the existing `draft` property: + +```python +@property +def meta_type(self) -> str: + return str(self.frontmatter.get("type", "")) + +@property +def meta_tags(self) -> str: + tags = self.frontmatter.get("tags", []) + if isinstance(tags, list): + return ", ".join(str(t) for t in tags) + return str(tags) if tags else "" + +@property +def meta_categories(self) -> str: + cats = self.frontmatter.get("categories", []) + if isinstance(cats, list): + return ", ".join(str(c) for c in cats) + return str(cats) if cats else "" + +@property +def meta_date(self) -> str: + raw = self.frontmatter.get("date", "") + if not raw: + return "" + return str(raw)[:10] # ISO date → "YYYY-MM-DD" +``` + +- [ ] **Step 4: Run tests to confirm they pass** + +```bash +pytest tests/test_models.py -v +``` + +Expected: all pass. + +- [ ] **Step 5: Commit** + +```bash +git add core/models.py tests/test_models.py +git commit -m "feat: add meta_type, meta_tags, meta_categories, meta_date properties to Article" +``` + +--- + +### Task 2: Render metadata in ArticleItem + +**Files:** +- Modify: `ui/articles_view.py` + +No automated tests for UI — verify manually. + +- [ ] **Step 1: Update ArticleItem to render two-line text** + +In `ui/articles_view.py`, replace the `ArticleItem.__init__` method. The first line keeps slug + translation badge (and `[DRAFT]` prefix). The second line shows metadata fields, omitting empty ones. + +Replace the existing `ArticleItem` class (lines 10-26) with: + +```python +class ArticleItem(QListWidgetItem): + def __init__(self, article: Article): + super().__init__() + self.article = article + if article.has_translation: + badge = f"🇬🇧 ✓" if article.lang == "it" else "🇮🇹 ✓" + else: + badge = f"🇬🇧 ✗" if article.lang == "it" else "🇮🇹 ✗" + line1 = f"{article.slug} [{badge}]" + if article.draft: + line1 = f"[DRAFT] {line1}" + + parts = [] + if article.meta_type: + parts.append(article.meta_type) + if article.meta_date: + parts.append(article.meta_date) + if article.meta_tags: + parts.append(f"#{article.meta_tags.replace(', ', ' #')}") + if article.meta_categories: + parts.append(f"[{article.meta_categories}]") + line2 = " ".join(parts) if parts else "" + + text = f"{line1}\n{line2}" if line2 else line1 + self.setText(text) + self.setSizeHint(QSize(0, 42) if line2 else QSize(0, 26)) + + if article.draft: + self.setForeground(QColor("#f59e0b")) + elif not article.has_translation: + self.setForeground(QColor("#ff6b6b")) +``` + +Also add `QSize` to the imports at the top of the file: + +```python +from PyQt6.QtCore import Qt, pyqtSignal, QSize +``` + +- [ ] **Step 2: Run the app and verify visually** + +```bash +python main.py +``` + +Check: +- Each article row shows two lines: slug + badge on line 1, metadata on line 2 +- Articles with no metadata (missing type/date/tags/categories) show single line +- Draft articles: amber color on both lines +- Missing-translation articles: red color +- Tags rendered as `#tag1 #tag2` +- Categories rendered as `[Cat1, Cat2]` +- Date rendered as `YYYY-MM-DD` +- Row height accommodates two lines without clipping + +- [ ] **Step 3: Run full test suite** + +```bash +pytest tests/ -v +``` + +Expected: all 22+ tests pass (UI change has no tests, but existing tests must not break). + +- [ ] **Step 4: Commit** + +```bash +git add ui/articles_view.py +git commit -m "feat: show type, date, tags, categories in article list rows" +``` |
