1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What This Is
PyQt6 desktop GUI for Linux that centralizes the danix.xyz Hugo blog publishing workflow. Centralizes: article management, translations (IT↔EN via RunPod), git operations, hugo server, media uploads, and taxonomy management.
Blog repo: `/home/danix/Programming/GIT/danix.xyz-hacker-theme`
Translation script: `/home/danix/bin/transart.py` (TranslateGemma 27b on RunPod)
Config file: `~/.config/my-publisher/config.toml`
## Commands
```bash
# Run app
python main.py
# Run all tests
pytest tests/ -v
# Run single test file
pytest tests/test_config.py -v
# Run single test
pytest tests/test_config.py::test_config_round_trips -v
# Install deps
pip install -r requirements.txt
```
## Architecture
Single Python process. Three layers:
**`core/`** — UI-agnostic business logic:
- `config.py` — load/save `~/.config/my-publisher/config.toml` via tomlkit
- `models.py` — `Article` dataclass + `ARTICLE_TYPES = ["Life", "Photo", "Link", "Quote", "Tech"]`
- `article_scanner.py` — scans `content/it/` and `content/en/`, builds `list[Article]`, detects translation pairs by matching slugs across languages
- `frontmatter.py` — parse/write Hugo TOML frontmatter (delimited by `+++`, not YAML `---`)
- `taxonomy.py` — load/save `docs/tags-it.txt` + `docs/tags-en.txt` (line-aligned pairs)
**`workers/`** — async operations via Qt signals:
- `git_worker.py` — `QThread` for pull, push master/production, `git rm`, restore deleted
- `hugo_worker.py` — `QProcess` for `hugo server -D`, streams stdout line by line
- `translation_worker.py` — `QProcess` for `transart.py`, streams stdout for progress display
Workers emit `output(str)`, `error(str)`, `finished(bool)` signals. UI connects to these — never blocks the main thread.
**`ui/`** — PyQt6 widgets:
- `main_window.py` — `QMainWindow` with sidebar + `QStackedWidget`. Sidebar has groups: CONTENUTO / WORKFLOW / DEPLOY. Uses `QFileSystemWatcher` on `content/it/` and `content/en/` to auto-refresh on external changes (e.g. Typora edits).
- Each sidebar section maps to a widget in the stack.
## Key Conventions
**Hugo frontmatter is TOML, not YAML.** Delimited by `+++`. Always use `tomlkit` (not `tomllib`) to preserve key ordering and comments when writing back.
**Translation pairs are matched by slug.** An IT article at `content/it/articles/my-post/index.md` and EN at `content/en/articles/my-post/index.md` share slug `my-post`. `article_scanner.py` builds the pairing.
**Git branches:** `master` = staging (hugo server testing), `production` = live deploy (post-receive hook on server).
**Media path convention:** Files upload to `static/uppies/YYYY/MM/filename`. Web path served as `/uppies/YYYY/MM/filename`.
**Tests are UI-free.** `core/` and `workers/` are tested with pytest + tmp_path fixtures. Qt UI components are not unit-tested — verify manually by running the app.
**Config path override in tests:** Pass `path` explicitly to `Config.load(path)` / `Config.save(path)` rather than monkeypatching the module-level constant.
## Spec and Plan
Full design spec: `docs/superpowers/specs/2026-05-01-my-publisher-design.md`
Implementation plan (20 tasks): `docs/superpowers/plans/2026-05-01-my-publisher.md`
Implementation is in progress — tasks 1–4 complete (scaffold, config, models, frontmatter parser). Tasks 5–20 pending.
|