From 351a8f0dd4e22689a609f4bdf517d38fcddb8935 Mon Sep 17 00:00:00 2001 From: baturns Date: Mon, 20 Apr 2026 22:43:00 +0300 Subject: [PATCH] docs(BAT-8): refresh README, add USAGE, screenshots, and docs skill - Expand README with full command table, links to English/Turkish guides, board screenshot - Add docs/USAGE.md mirroring KULLANIM; update KULLANIM (tw back, keys, :, Esc, TASKWAL_DIR fix) - Add docs/images board/stats PNGs via scripts/generate_doc_screenshots.py (Pillow) - Add .cursor/skills/taskwal-project-docs for keeping docs in sync; gitignore .docgen_pillow Made-with: Cursor --- .cursor/skills/taskwal-project-docs/SKILL.md | 40 ++++ .gitignore | 1 + README.md | 43 +++- docs/KULLANIM.md | 28 ++- docs/USAGE.md | 196 +++++++++++++++++++ docs/images/board.png | Bin 0 -> 18885 bytes docs/images/stats.png | Bin 0 -> 18937 bytes scripts/generate_doc_screenshots.py | 150 ++++++++++++++ 8 files changed, 445 insertions(+), 13 deletions(-) create mode 100644 .cursor/skills/taskwal-project-docs/SKILL.md create mode 100644 docs/USAGE.md create mode 100644 docs/images/board.png create mode 100644 docs/images/stats.png create mode 100644 scripts/generate_doc_screenshots.py diff --git a/.cursor/skills/taskwal-project-docs/SKILL.md b/.cursor/skills/taskwal-project-docs/SKILL.md new file mode 100644 index 0000000..5bd641e --- /dev/null +++ b/.cursor/skills/taskwal-project-docs/SKILL.md @@ -0,0 +1,40 @@ +--- +name: taskwal-project-docs +description: Maintains TaskWAL user-facing documentation in English and Turkish and TUI screenshots when the CLI, board, or on-disk layout changes. Use when editing src/, adding or changing tw subcommands or TUI behavior, updating README or docs, or when the user asks to sync or refresh project documentation. +--- + +# TaskWAL project documentation + +## Files to keep aligned + +| Asset | Role | +| ----- | ---- | +| [README.md](../../../README.md) | Short overview, quick reference, links to full guides | +| [docs/USAGE.md](../../../docs/USAGE.md) | Full English user guide | +| [docs/KULLANIM.md](../../../docs/KULLANIM.md) | Full Turkish user guide (mirror of USAGE) | +| [docs/images/](../../../docs/images/) | `board.png`, `stats.png` for README and guides | + +## When to update + +1. **CLI change** (`src/main.rs`, `src/commands.rs`): reflect new/changed subcommands, flags, or id rules in README (table or examples), then **both** USAGE and KULLANIM. +2. **TUI change** (`src/ui/`): update keyboard tables, command-line (`:`) behavior, and **refresh screenshots** if the visible layout or colors change materially. +3. **Data paths / env**: keep README, USAGE, and KULLANIM consistent (`TASKWAL_DIR`, WAL path). +4. **Analytics text** (`tw stats` output vs stats screen): keep USAGE/KULLANIM descriptions in sync with `src/` and [src/ui/stats.rs](../../../src/ui/stats.rs). + +## Screenshots + +- Regenerate stylized PNGs after meaningful UI changes: + + ```bash + pip install --target .docgen_pillow pillow # once; .docgen_pillow is gitignored + PYTHONPATH=.docgen_pillow python3 scripts/generate_doc_screenshots.py + ``` + +- Commit updated files under `docs/images/`. The script draws an approximation of the TUI; replace with real terminal captures if you need pixel-perfect fidelity. + +## Checklist + +- [ ] README links to USAGE and KULLANIM +- [ ] English and Turkish guides describe the same commands and keys +- [ ] Image paths in markdown use `images/...` from `docs/*.md` and `docs/images/...` from README root +- [ ] No drive-by edits to unrelated markdown diff --git a/.gitignore b/.gitignore index ecbd5bb..449d372 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target **/*.rs.bk .DS_Store +.docgen_pillow/ diff --git a/README.md b/README.md index cdc95c3..f555f43 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Local-first task tracker using an append-only JSONL write-ahead log (`~/.taskwal/wal.log` on Unix, `%USERPROFILE%\.taskwal\wal.log` on Windows). +![TaskWAL board (TUI)](docs/images/board.png) + ## Build Requires [Rust](https://rustup.rs/) 1.70+. @@ -13,33 +15,58 @@ cargo build --release ## Cross-platform -- **macOS / Linux / Windows**: the same codebase; `crossterm` + `ratatui` work on common terminals. +- **macOS / Linux / Windows:** same codebase; `crossterm` + `ratatui` work on common terminals. - Build on each OS you ship for, or use cross-compilation (e.g. `cargo build --release --target x86_64-pc-windows-gnu` from a configured toolchain). -## Usage +## Documentation + +- **English (full guide):** [docs/USAGE.md](docs/USAGE.md) +- **Türkçe (tam kılavuz):** [docs/KULLANIM.md](docs/KULLANIM.md) -Türkçe ayrıntılı kılavuz: [docs/KULLANIM.md](docs/KULLANIM.md). +## Usage (quick reference) ```bash tw add "Write API" --tag backend -tw start 01HX… # prefix match if unique +tw start 01HX… # prefix match if unique tw done 01HX… +tw back 01HX… # one step back: Done→Doing or Doing→Todo +tw edit 01HX… "New title" +tw note 01HX… "Blocked on API" +tw rm 01HX… + tw ls # Todo/Doing: all open tasks; Done: today (local) by default tw ls --all # Done column: all completed tasks tw ls --date 2026-04-01 -tw stats -tw board + +tw board # interactive Kanban TUI (same view flags as ls) +tw stats # aggregate stats (all-time), text output tw log # raw WAL JSON lines ``` +### Commands + +| Command | Purpose | +|--------|---------| +| `add ` | New task (Todo); `--tag` / `-t` comma-separated tags | +| `start <id>` | Move to Doing | +| `done <id>` | Move to Done | +| `back <id>` | Move one column backward | +| `edit <id> <title>` | Rename task | +| `note <id> <text>` | Append a note | +| `rm <id>` | Remove task (append-only delete event in WAL) | +| `ls` | Print board columns for the current view (`--all`, `--date`) | +| `board` | Full-screen TUI board (`--all`, `--date`) | +| `stats` | Print statistics | +| `log` | Dump WAL as JSON lines | + ### Daily view rules -- **Todo / Doing:** every open task is listed (carry-over across days; nothing unfinished disappears from the default view). +- **Todo / Doing:** every open task is listed (carry-over across days). - **Done:** by default, tasks completed on **today’s local calendar date**. Use `--all` or `--date` to widen. ## Environment -- **`TASKWAL_DIR`**: override the data directory (used by tests and for custom locations). WAL file: `$TASKWAL_DIR/wal.log`. +- **`TASKWAL_DIR`:** override the data directory (used by tests and for custom locations). WAL file: `$TASKWAL_DIR/wal.log`. ## License diff --git a/docs/KULLANIM.md b/docs/KULLANIM.md index c17d55a..a5bcf21 100644 --- a/docs/KULLANIM.md +++ b/docs/KULLANIM.md @@ -2,6 +2,8 @@ Bu belge, projenin **mevcut sürümü** için komut satırı ve TUI kullanımını anlatır. +İngilizce aynı seviyede kılavuz: [USAGE.md](USAGE.md). + ## Uygulama nedir? TaskWAL, görevlerinizi **yerel bilgisayarınızda** tutan bir iş takip aracıdır. Tüm değişiklikler, silme dahil, **append-only** bir günlük dosyasına (WAL) yazılır; uygulama bu dosyayı okuyup güncel pano (Todo / Doing / Done) durumunu **yeniden oynatarak** (replay) üretir. @@ -17,7 +19,7 @@ TaskWAL, görevlerinizi **yerel bilgisayarınızda** tutan bir iş takip aracıd Özel konum için ortam değişkeni: -- `**TASKWAL_DIR`**: Veri klasörü. WAL yolu: `$TASKWAL_DIR/wal.log` (Windows’ta `%TASKWAL_DIR%\wal.log`). +- **`TASKWAL_DIR`**: Veri klasörü. WAL yolu: `$TASKWAL_DIR/wal.log` (Windows’ta `%TASKWAL_DIR%\wal.log`). ## Kurulum ve `tw` komutu @@ -51,8 +53,8 @@ tw <komut> --help **Done** kolonu: - **Varsayılan:** Yerel saat diliminde **seçilen takvim gününde** tamamlanan görevler. Seçim belirtilmezse gün = **bugün**. -- `**--all`:** Tamamlanan **tüm** görevler (geçmiş dahil); Todo/Doing yine tüm açık işlerdir. -- `**--date YYYY-MM-DD`:** Done kolonu yalnızca o yerel güne düşen tamamlamalara göre süzülür. +- **`--all`:** Tamamlanan **tüm** görevler (geçmiş dahil); Todo/Doing yine tüm açık işlerdir. +- **`--date YYYY-MM-DD`:** Done kolonu yalnızca o yerel güne düşen tamamlamalara göre süzülür. `--all` ile `--date` **birlikte kullanılamaz.** @@ -69,7 +71,7 @@ tw add "API taslağını yaz" tw add "Review" --tag backend,urgent ``` -- `**--tag` / `-t`:** Virgülle ayrılmış etiket listesi. +- **`--tag` / `-t`:** Virgülle ayrılmış etiket listesi. ### `tw start <id>` @@ -79,6 +81,10 @@ Görevi **Doing** kolonuna taşır. İlk kez Doing’e geçişte “başlangıç Görevi **Done** kolonuna taşır; tamamlanma zamanı kaydedilir. +### `tw back <id>` + +Görevi **bir kolon geri** alır: Done → Doing → Todo (uygun olduğunda). + ### `tw edit <id> <yeni başlık>` Başlığı günceller. @@ -115,6 +121,10 @@ tw board --all tw board --date 2026-04-01 ``` +![Board TUI](images/board.png) + +**Seçili kolon** kenarlığı vurgulanır. **Seçili satır** açık ve koyu temalarda okunaklı görünsün diye **turuncu** arka plan ve kalın yazı ile gösterilir. + **Klavye (board ekranı):** @@ -124,10 +134,14 @@ tw board --date 2026-04-01 | `↑` / `↓` | Seçili kolonda satır | | `s` | Seçili görevi Doing’e al | | `d` | Seçili görevi Done’a al | +| `b` | Seçili görevi bir kolon geri al (Done→Doing→Todo) | | `a` | Done kolonu: bugünün tamamlananları ↔ tüm tamamlananlar arasında geçiş | | `g` | İstatistik ekranına geç | | `q` | Çıkış | +| `:` | Komut satırı (aşağıya bakın) | +| `Esc` | Komut satırında iptal | +**Komut satırı (`:`):** Örneğin `add Yeni görev` veya `start 01ABC123` yazın (`tw` öneki isteğe bağlı). **Enter** ile çalıştırın, **Esc** ile iptal. **İstatistik ekranı:** @@ -149,7 +163,11 @@ Yeni görev **CLI** ile eklenir: `tw add "…"`. - Ortalama **lead** süresi (gün): oluşturma → tamamlanma - Aktif gün başına düşen ortalama tamamlanan iş - Yerel günlere göre **streak** (ardışık günler) -- Son günlerin kısa dökümü +- Son günlerin kısa dökümü + +`tw board` içindeki tam ekran istatistik görünümü: + +![İstatistik ekranı](images/stats.png) ### `tw log` diff --git a/docs/USAGE.md b/docs/USAGE.md new file mode 100644 index 0000000..a6a07ee --- /dev/null +++ b/docs/USAGE.md @@ -0,0 +1,196 @@ +# TaskWAL (`tw`) — User guide + +This document describes the current CLI and TUI for this project. + +## What is TaskWAL? + +TaskWAL is a **local-first** task tracker. Every change, including deletes, is appended to a **write-ahead log** (WAL) file. The app **replays** that log to build the current board (Todo / Doing / Done). + +## Data location + +| Platform | Default directory | WAL file | +| ----------- | ------------------------ | --------- | +| macOS/Linux | `~/.taskwal/` | `wal.log` | +| Windows | `%USERPROFILE%\.taskwal\` | `wal.log` | + +Override with environment variable: + +- **`TASKWAL_DIR`:** data directory. WAL path: `$TASKWAL_DIR/wal.log` (on Windows, `%TASKWAL_DIR%\wal.log`). + +## Install and the `tw` command + +After building the project: + +```bash +cargo install --path /path/to/taskwal --force +``` + +This usually installs `tw` to `~/.cargo/bin/tw` (Windows: `%USERPROFILE%\.cargo\bin\tw.exe`). If `cargo` is not on your PATH: + +```bash +. "$HOME/.cargo/env" # macOS/Linux +``` + +Re-run `cargo install --path ... --force` after updates. + +Help: + +```bash +tw --help +tw <command> --help +``` + +--- + +## Daily view rules (`ls` and `board`) + +**Todo** and **Doing:** list **all** incomplete tasks, regardless of creation day. Open work carries over to the next day. + +**Done** column: + +- **Default:** tasks completed on the selected **local calendar day**. If you do not pass a date, that day is **today**. +- **`--all`:** all completed tasks (history included); Todo/Doing still show all open work. +- **`--date YYYY-MM-DD`:** Done column filtered to completions on that local day. + +`--all` and **`--date`** cannot be used together. + +--- + +## Commands + +### `tw add <title>` + +Creates a task (Todo by default). Creation day is the current local date. + +```bash +tw add "Draft API" +tw add "Review" --tag backend,urgent +``` + +- **`--tag` / `-t`:** comma-separated tags. + +### `tw start <id>` + +Moves the task to **Doing**. The first move to Doing records a **start** time. + +### `tw done <id>` + +Moves the task to **Done** and records completion time. + +### `tw back <id>` + +Moves one step backward: **Done → Doing → Todo** (when allowed). + +### `tw edit <id> <new title>` + +Renames the task. + +### `tw note <id> <text>` + +Appends a note (previous notes are kept). + +### `tw rm <id>` + +Removes the task from the board (a delete event is appended to the WAL). + +### Task id (`id`) + +Full ULID or a **unique prefix** (e.g. first 8 characters). Ambiguous or missing matches are errors. An empty prefix is not allowed. + +### `tw ls` + +Text view of Todo / Doing / Done for the current view. + +```bash +tw ls +tw ls --all +tw ls --date 2026-04-01 +``` + +### `tw board` + +Full-screen **Kanban** TUI (Ratatui). Same view options as `ls`: + +```bash +tw board +tw board --all +tw board --date 2026-04-01 +``` + +![Board TUI](images/board.png) + +The **focused column** highlights its border. The **selected row** uses an **orange** background with bold text so the cursor stays visible on light and dark terminal themes. + +**Board keys:** + +| Key | Action | +| --------- | ------ | +| `Tab` | Next column (Todo → Doing → Done) | +| `↑` / `↓` | Move selection in the current column | +| `s` | Move selected task to Doing | +| `d` | Move selected task to Done | +| `b` | Move selected task one column back | +| `a` | Toggle Done column: today vs all completed | +| `g` | Open stats screen | +| `q` | Quit | +| `:` | Command line (see below) | +| `Esc` | Cancel command line | + +**Command line (`:`):** type a line such as `add My task` or `start 01ABC123` (optional `tw` prefix). Press **Enter** to run, **Esc** to cancel. + +**Stats screen:** + +| Key | Action | +| ---------- | ------------- | +| `g`, `Esc` | Back to board | +| `q` | Quit app | + +New tasks can also be added from the shell with `tw add "…"`. + +### `tw stats` (text output) + +Prints **all-time** aggregates from completed tasks: + +- Total completed count +- Average **cycle** time (days): first start or creation → completion +- Average **lead** time (days): creation → completion +- Average completed tasks per **active** day +- Local **streak** (consecutive days) +- Short recent-day breakdown + +The full-screen stats view inside `tw board` looks like this: + +![Stats screen](images/stats.png) + +### `tw log` + +Prints raw WAL lines as JSON (backup or debugging). + +--- + +## Example session + +```bash +tw add "Morning standup" +tw add "PR review" --tag code + +tw ls +tw start 01ABC123 +tw done 01ABC123 + +tw stats +tw board +``` + +--- + +## Windows notes + +- **Build:** `cargo build --release` produces `target\release\tw.exe` for distribution. +- **Terminal:** Windows Terminal or another modern console is recommended; the TUI works in most environments. + +--- + +## License + +As stated in `Cargo.toml` (e.g. MIT OR Apache-2.0). diff --git a/docs/images/board.png b/docs/images/board.png new file mode 100644 index 0000000000000000000000000000000000000000..adf7190f4587ac3b63a0fc18e47a4533fd23d848 GIT binary patch literal 18885 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 literal 0 HcmV?d00001 diff --git a/docs/images/stats.png b/docs/images/stats.png new file mode 100644 index 0000000000000000000000000000000000000000..893e3d11b988a4d9a2ced4999d30c7f6522c3d50 GIT binary patch literal 18937 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 literal 0 HcmV?d00001 diff --git a/scripts/generate_doc_screenshots.py b/scripts/generate_doc_screenshots.py new file mode 100644 index 0000000..a0ee03d --- /dev/null +++ b/scripts/generate_doc_screenshots.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +"""Generate stylized PNG screenshots under docs/images/ for README and guides. + +Requires Pillow: pip install pillow + (or: pip install --target .docgen_pillow pillow && PYTHONPATH=.docgen_pillow python3 ...) + +This renders a visual approximation of the TUI, not a live terminal capture. +""" + +from __future__ import annotations + +import os +from pathlib import Path + +try: + from PIL import Image, ImageDraw, ImageFont +except ImportError as e: + raise SystemExit( + "Pillow is required: pip install pillow\n" + " or: pip install --target .docgen_pillow pillow && PYTHONPATH=.docgen_pillow python3 scripts/generate_doc_screenshots.py" + ) from e + +ROOT = Path(__file__).resolve().parents[1] +OUT = ROOT / "docs" / "images" + +BG = (12, 12, 12) +FG = (230, 230, 230) +CYAN = (0, 200, 220) +YELLOW = (220, 220, 100) +BLUE = (120, 160, 255) +GREEN = (120, 220, 160) +GRAY = (100, 100, 100) +ORANGE = (255, 165, 0) +BLACK = (0, 0, 0) + + +def _font(size: int) -> ImageFont.FreeTypeFont | ImageFont.ImageFont: + for path in ( + "/System/Library/Fonts/Supplemental/Courier New.ttf", + "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", + "/usr/share/fonts/TTF/DejaVuSansMono.ttf", + ): + if os.path.isfile(path): + return ImageFont.truetype(path, size) + return ImageFont.load_default() + + +def draw_board(path: Path) -> None: + w, h = 880, 520 + im = Image.new("RGB", (w, h), BG) + dr = ImageDraw.Draw(im) + mono = _font(14) + small = _font(12) + + today = "2026-04-20" + header = f" TaskWAL — today {today} | Done: {today} (local) " + dr.rectangle([4, 4, w - 5, 28], outline=CYAN, width=1) + dr.text((10, 8), header, fill=CYAN, font=mono) + + col_w = (w - 24) // 3 + y0 = 36 + col_h = h - y0 - 120 + titles = [("TODO", YELLOW, 2), ("DOING", BLUE, 1), ("DONE", GREEN, 1)] + rows_todo = [ + (" o [01ABC123] Write API docs", False), + (" o [01DEF456] Review PR", True), + ] + rows_doing = [(" * [01GHI789] Integrate auth", False)] + rows_done = [(" x [01JKL012] Initial scaffold", False)] + + def col_block( + x: int, + title: str, + border: tuple[int, int, int], + rows: list[tuple[str, bool]], + selected: bool, + ) -> None: + dr.rectangle([x, y0, x + col_w - 4, y0 + col_h], outline=border, width=2 if selected else 1) + dr.text((x + 8, y0 + 4), f" {title} ({len(rows)}) ", fill=border, font=small) + yy = y0 + 28 + for line, is_sel in rows: + if is_sel: + bbox = dr.textbbox((x + 10, yy), line, font=mono) + dr.rectangle([bbox[0] - 2, bbox[1] - 1, bbox[2] + 2, bbox[3] + 1], fill=ORANGE) + dr.text((x + 10, yy), line, fill=BLACK, font=mono) + else: + dr.text((x + 10, yy), line, fill=FG, font=mono) + yy += 20 + + col_block(8, "TODO", titles[0][1], rows_todo, True) + col_block(8 + col_w, "DOING", titles[1][1], rows_doing, False) + col_block(8 + 2 * col_w, "DONE", titles[2][1], rows_done, False) + + fy = y0 + col_h + 8 + dr.rectangle([4, fy, w - 5, fy + 32], outline=GRAY, width=1) + dr.text((10, fy + 8), "> ", fill=GRAY, font=mono) + dr.text((10, fy + 52), " command (press :) ", fill=GRAY, font=small) + hint = " s start | d done | b back | a Done view | Tab | g stats | q | : command | Esc " + dr.text((10, h - 28), hint, fill=GRAY, font=small) + + im.save(path, "PNG") + + +def draw_stats(path: Path) -> None: + w, h = 640, 480 + im = Image.new("RGB", (w, h), BG) + dr = ImageDraw.Draw(im) + mono = _font(15) + small = _font(13) + + title = " Stats (all-time) | g / Esc back | q quit " + dr.rectangle([4, 4, w - 5, 28], outline=CYAN, width=1) + dr.text((10, 8), title, fill=CYAN, font=small) + + body = """ + Total completed : 42 + + Avg cycle time : 2.3 d + + Avg lead time : 4.1 d + + Avg per active day: 3.2 tasks + + Streak (local) : 5 d + + Recent days: + 2026-04-20 -> 4 done + 2026-04-19 -> 2 done + 2026-04-18 -> 5 done +""".strip( + "\n" + ) + y = 44 + for line in body.split("\n"): + dr.text((8, y), line, fill=FG, font=mono) + y += 22 + + im.save(path, "PNG") + + +def main() -> None: + OUT.mkdir(parents=True, exist_ok=True) + draw_board(OUT / "board.png") + draw_stats(OUT / "stats.png") + print(f"Wrote {OUT / 'board.png'}") + print(f"Wrote {OUT / 'stats.png'}") + + +if __name__ == "__main__": + main()