parch 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. parch-0.1.0/.github/dependabot.yml +22 -0
  2. parch-0.1.0/.github/workflows/ci.yml +21 -0
  3. parch-0.1.0/.github/workflows/publish.yml +68 -0
  4. parch-0.1.0/.github/workflows/readme-previews.yml +54 -0
  5. parch-0.1.0/.gitignore +10 -0
  6. parch-0.1.0/LICENSE +25 -0
  7. parch-0.1.0/PKG-INFO +199 -0
  8. parch-0.1.0/README.md +151 -0
  9. parch-0.1.0/docs/samples/158x210-mos-left/annual.svg +1 -0
  10. parch-0.1.0/docs/samples/158x210-mos-left/colophon.svg +1 -0
  11. parch-0.1.0/docs/samples/158x210-mos-left/contents.svg +1 -0
  12. parch-0.1.0/docs/samples/158x210-mos-left/cover.svg +1 -0
  13. parch-0.1.0/docs/samples/158x210-mos-left/daily-jan1.svg +1 -0
  14. parch-0.1.0/docs/samples/158x210-mos-left/monthly-jan.svg +1 -0
  15. parch-0.1.0/docs/samples/158x210-mos-left/notes-jan1.svg +1 -0
  16. parch-0.1.0/docs/samples/158x210-mos-left/quarterly-q1.svg +1 -0
  17. parch-0.1.0/docs/samples/158x210-mos-left/weekly-w01.svg +1 -0
  18. parch-0.1.0/pyproject.toml +55 -0
  19. parch-0.1.0/src/parch/__init__.py +17 -0
  20. parch-0.1.0/src/parch/__main__.py +4 -0
  21. parch-0.1.0/src/parch/calendar/__init__.py +39 -0
  22. parch-0.1.0/src/parch/calendar/dated_note.py +34 -0
  23. parch-0.1.0/src/parch/calendar/day.py +181 -0
  24. parch-0.1.0/src/parch/calendar/month.py +83 -0
  25. parch-0.1.0/src/parch/calendar/quarter.py +67 -0
  26. parch-0.1.0/src/parch/calendar/week.py +71 -0
  27. parch-0.1.0/src/parch/cli.py +285 -0
  28. parch-0.1.0/src/parch/config.py +125 -0
  29. parch-0.1.0/src/parch/data/__init__.py +1 -0
  30. parch-0.1.0/src/parch/data/configs/158x210-mos-left-lined.toml +103 -0
  31. parch-0.1.0/src/parch/data/configs/158x210-mos-left.toml +99 -0
  32. parch-0.1.0/src/parch/data/configs/158x210-mos-right.toml +102 -0
  33. parch-0.1.0/src/parch/data/configs/kindle-scribe.toml +97 -0
  34. parch-0.1.0/src/parch/data/configs/supernote-nomad-mos-right.toml +116 -0
  35. parch-0.1.0/src/parch/data/configs/supernote-nomad.toml +113 -0
  36. parch-0.1.0/src/parch/data/locales/en.toml +84 -0
  37. parch-0.1.0/src/parch/devices.py +76 -0
  38. parch-0.1.0/src/parch/i18n.py +83 -0
  39. parch-0.1.0/src/parch/models/__init__.py +22 -0
  40. parch-0.1.0/src/parch/models/base.py +35 -0
  41. parch-0.1.0/src/parch/models/device.py +400 -0
  42. parch-0.1.0/src/parch/models/locale.py +94 -0
  43. parch-0.1.0/src/parch/mos/__init__.py +19 -0
  44. parch-0.1.0/src/parch/mos/builder.py +120 -0
  45. parch-0.1.0/src/parch/mos/components/__init__.py +15 -0
  46. parch-0.1.0/src/parch/mos/components/daily_notes.py +49 -0
  47. parch-0.1.0/src/parch/mos/components/daily_priorities.py +27 -0
  48. parch-0.1.0/src/parch/mos/components/daily_schedule.py +58 -0
  49. parch-0.1.0/src/parch/mos/components/little_calendar.py +138 -0
  50. parch-0.1.0/src/parch/mos/components/months_menu.py +53 -0
  51. parch-0.1.0/src/parch/mos/components/quarters_menu.py +43 -0
  52. parch-0.1.0/src/parch/mos/configurator.py +74 -0
  53. parch-0.1.0/src/parch/mos/contents_mark.py +107 -0
  54. parch-0.1.0/src/parch/mos/coordinator.py +94 -0
  55. parch-0.1.0/src/parch/mos/manifest.py +37 -0
  56. parch-0.1.0/src/parch/mos/navigation.py +161 -0
  57. parch-0.1.0/src/parch/mos/page_data.py +24 -0
  58. parch-0.1.0/src/parch/mos/pages/__init__.py +6 -0
  59. parch-0.1.0/src/parch/mos/pages/daily.py +112 -0
  60. parch-0.1.0/src/parch/mos/pages/monthly.py +126 -0
  61. parch-0.1.0/src/parch/mos/pages/quarterly.py +69 -0
  62. parch-0.1.0/src/parch/mos/pages/weekly.py +60 -0
  63. parch-0.1.0/src/parch/mos/preamble.py +129 -0
  64. parch-0.1.0/src/parch/mos/sections/__init__.py +29 -0
  65. parch-0.1.0/src/parch/mos/sections/_shared.py +33 -0
  66. parch-0.1.0/src/parch/mos/sections/annual.py +85 -0
  67. parch-0.1.0/src/parch/mos/sections/cover_plain.py +50 -0
  68. parch-0.1.0/src/parch/mos/sections/daily.py +58 -0
  69. parch-0.1.0/src/parch/mos/sections/daily_notes.py +108 -0
  70. parch-0.1.0/src/parch/mos/sections/habits.py +221 -0
  71. parch-0.1.0/src/parch/mos/sections/index.py +126 -0
  72. parch-0.1.0/src/parch/mos/sections/meetings.py +216 -0
  73. parch-0.1.0/src/parch/mos/sections/monthly.py +77 -0
  74. parch-0.1.0/src/parch/mos/sections/projects.py +225 -0
  75. parch-0.1.0/src/parch/mos/sections/quarterly.py +86 -0
  76. parch-0.1.0/src/parch/mos/sections/review.py +274 -0
  77. parch-0.1.0/src/parch/mos/sections/tasks.py +272 -0
  78. parch-0.1.0/src/parch/mos/sections/weekly.py +86 -0
  79. parch-0.1.0/src/parch/provenance.py +209 -0
  80. parch-0.1.0/src/parch/sections/__init__.py +3 -0
  81. parch-0.1.0/src/parch/sections/colophon.py +333 -0
  82. parch-0.1.0/src/parch/services/__init__.py +4 -0
  83. parch-0.1.0/src/parch/services/compile.py +314 -0
  84. parch-0.1.0/src/parch/services/config_file.py +356 -0
  85. parch-0.1.0/src/parch/services/generate.py +25 -0
  86. parch-0.1.0/src/parch/services/preview_svg.py +244 -0
  87. parch-0.1.0/src/parch/toml_config.py +545 -0
  88. parch-0.1.0/tests/__init__.py +0 -0
  89. parch-0.1.0/tests/calendar/__init__.py +0 -0
  90. parch-0.1.0/tests/calendar/test_day.py +78 -0
  91. parch-0.1.0/tests/calendar/test_month.py +41 -0
  92. parch-0.1.0/tests/calendar/test_quarter.py +49 -0
  93. parch-0.1.0/tests/calendar/test_week.py +49 -0
  94. parch-0.1.0/tests/conftest.py +2 -0
  95. parch-0.1.0/tests/helpers.py +84 -0
  96. parch-0.1.0/tests/mos/__init__.py +0 -0
  97. parch-0.1.0/tests/mos/test_annual.py +103 -0
  98. parch-0.1.0/tests/mos/test_daily.py +256 -0
  99. parch-0.1.0/tests/mos/test_daily_notes.py +225 -0
  100. parch-0.1.0/tests/mos/test_little_calendar.py +125 -0
  101. parch-0.1.0/tests/mos/test_manifest.py +9 -0
  102. parch-0.1.0/tests/mos/test_monthly.py +212 -0
  103. parch-0.1.0/tests/mos/test_navigation.py +134 -0
  104. parch-0.1.0/tests/mos/test_quarterly.py +205 -0
  105. parch-0.1.0/tests/mos/test_weekly.py +198 -0
  106. parch-0.1.0/tests/test_colophon.py +674 -0
  107. parch-0.1.0/tests/test_config.py +50 -0
  108. parch-0.1.0/tests/test_cover.py +37 -0
  109. parch-0.1.0/tests/test_cover_visual.py +38 -0
  110. parch-0.1.0/tests/test_habits.py +702 -0
  111. parch-0.1.0/tests/test_habits_visual.py +36 -0
  112. parch-0.1.0/tests/test_i18n.py +104 -0
  113. parch-0.1.0/tests/test_index.py +267 -0
  114. parch-0.1.0/tests/test_meetings.py +336 -0
  115. parch-0.1.0/tests/test_meetings_visual.py +110 -0
  116. parch-0.1.0/tests/test_models.py +209 -0
  117. parch-0.1.0/tests/test_mos_handedness.py +252 -0
  118. parch-0.1.0/tests/test_new.py +296 -0
  119. parch-0.1.0/tests/test_open_resolved_zip.py +40 -0
  120. parch-0.1.0/tests/test_preview_svg.py +184 -0
  121. parch-0.1.0/tests/test_projects.py +449 -0
  122. parch-0.1.0/tests/test_projects_visual.py +84 -0
  123. parch-0.1.0/tests/test_provenance.py +129 -0
  124. parch-0.1.0/tests/test_review.py +540 -0
  125. parch-0.1.0/tests/test_scratch_pad.py +269 -0
  126. parch-0.1.0/tests/test_tasks.py +464 -0
  127. parch-0.1.0/tests/test_toml_config.py +538 -0
  128. parch-0.1.0/tests/test_toml_omit_sections.py +217 -0
  129. parch-0.1.0/tests/test_typst_asset.py +173 -0
  130. parch-0.1.0/tests/toml_fixtures.py +162 -0
  131. parch-0.1.0/tests/visual.py +152 -0
  132. parch-0.1.0/uv.lock +322 -0
@@ -0,0 +1,22 @@
1
+ # Dependabot: GitHub Actions and uv (pyproject.toml + uv.lock)
2
+ version: 2
3
+ updates:
4
+ - package-ecosystem: github-actions
5
+ directory: /
6
+ schedule:
7
+ interval: weekly
8
+ day: monday
9
+ groups:
10
+ github-actions:
11
+ patterns:
12
+ - "*"
13
+
14
+ - package-ecosystem: uv
15
+ directory: /
16
+ schedule:
17
+ interval: weekly
18
+ day: monday
19
+ groups:
20
+ python:
21
+ patterns:
22
+ - "*"
@@ -0,0 +1,21 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v7
13
+ - uses: astral-sh/setup-uv@v7
14
+ - name: Install poppler-utils
15
+ run: sudo apt-get update && sudo apt-get install -y poppler-utils
16
+ - run: uv sync --group dev
17
+ - run: uv run pytest
18
+ - name: Generate Nomad PDF
19
+ run: |
20
+ uv run parch generate supernote-nomad -w out/nomad
21
+ test -s out/nomad/index.pdf
@@ -0,0 +1,68 @@
1
+ name: Publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ target:
10
+ description: "Publish target"
11
+ required: true
12
+ type: choice
13
+ options:
14
+ - testpypi
15
+ - pypi
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ build:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
25
+ with:
26
+ persist-credentials: false
27
+ - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
28
+ with:
29
+ enable-cache: false
30
+ - run: uv build
31
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
32
+ with:
33
+ name: dist
34
+ path: dist/
35
+
36
+ pypi:
37
+ needs: build
38
+ if: github.event_name == 'push' || inputs.target == 'pypi'
39
+ runs-on: ubuntu-latest
40
+ environment:
41
+ name: pypi
42
+ url: https://pypi.org/p/parch
43
+ permissions:
44
+ id-token: write
45
+ steps:
46
+ - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
47
+ with:
48
+ name: dist
49
+ path: dist
50
+ - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
51
+
52
+ testpypi:
53
+ needs: build
54
+ if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
55
+ runs-on: ubuntu-latest
56
+ environment:
57
+ name: testpypi
58
+ url: https://test.pypi.org/p/parch
59
+ permissions:
60
+ id-token: write
61
+ steps:
62
+ - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
63
+ with:
64
+ name: dist
65
+ path: dist
66
+ - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
67
+ with:
68
+ repository-url: https://test.pypi.org/legacy/
@@ -0,0 +1,54 @@
1
+ name: README preview SVGs
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ paths:
7
+ - "src/**"
8
+ - "src/parch/data/configs/158x210-mos-left.toml"
9
+
10
+ concurrency:
11
+ group: readme-previews
12
+ cancel-in-progress: false
13
+
14
+ permissions:
15
+ contents: write
16
+ pull-requests: write
17
+
18
+ jobs:
19
+ regen:
20
+ if: github.actor != 'github-actions[bot]'
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v7
24
+ - uses: astral-sh/setup-uv@v7
25
+ - run: uv sync --group dev
26
+ - name: Regenerate 158×210 sample SVGs
27
+ run: uv run parch preview-svg 158x210-mos-left --samples
28
+ - name: Open a PR when SVGs changed
29
+ env:
30
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
31
+ run: |
32
+ git add docs/samples/158x210-mos-left
33
+ if git diff --cached --quiet; then
34
+ echo "preview SVGs unchanged"
35
+ exit 0
36
+ fi
37
+ git config user.name "github-actions[bot]"
38
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
39
+ git switch -C chore/readme-preview-svgs
40
+ git commit -m "Regenerate 158×210 README preview SVGs."
41
+ git push --force-with-lease origin chore/readme-preview-svgs
42
+ existing="$(gh pr list --head chore/readme-preview-svgs --state open --json number --jq '.[0].number // empty')"
43
+ if [ -n "$existing" ]; then
44
+ echo "updated PR #$existing"
45
+ exit 0
46
+ fi
47
+ gh pr create --base master --head chore/readme-preview-svgs \
48
+ --title "Regenerate 158×210 README preview SVGs" \
49
+ --body "$(cat <<'EOF'
50
+ Bot-generated Typst preview SVGs for the README. Merge after CI passes.
51
+
52
+ This PR is opened instead of pushing to master so the required \`test\` check can run.
53
+ EOF
54
+ )"
parch-0.1.0/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ .venv
2
+ out/
3
+ .tools/
4
+ __pycache__/
5
+ *.pyc
6
+ .pytest_cache
7
+ dist
8
+ *.egg-info
9
+ .ruff_cache
10
+ .mypy_cache
parch-0.1.0/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 PDF Planner Project
4
+ Copyright (c) 2026 Vitaliy Kudryk (original LYP)
5
+
6
+ This software is a Python port of Vitaliy Kudryk's LYP (latex yearly planner),
7
+ originally licensed under the MIT License (2026).
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in
17
+ all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
+ THE SOFTWARE.
parch-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,199 @@
1
+ Metadata-Version: 2.5
2
+ Name: parch
3
+ Version: 0.1.0
4
+ Summary: parch -- pages for e-ink.
5
+ Project-URL: Homepage, https://github.com/yyolk/parch
6
+ Project-URL: Repository, https://github.com/yyolk/parch
7
+ Project-URL: Issues, https://github.com/yyolk/parch/issues
8
+ Author-email: Joseph Chiocchi <joe@yolk.cc>
9
+ License: The MIT License (MIT)
10
+
11
+ Copyright (c) 2026 PDF Planner Project
12
+ Copyright (c) 2026 Vitaliy Kudryk (original LYP)
13
+
14
+ This software is a Python port of Vitaliy Kudryk's LYP (latex yearly planner),
15
+ originally licensed under the MIT License (2026).
16
+
17
+ Permission is hereby granted, free of charge, to any person obtaining a copy
18
+ of this software and associated documentation files (the "Software"), to deal
19
+ in the Software without restriction, including without limitation the rights
20
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21
+ copies of the Software, and to permit persons to whom the Software is
22
+ furnished to do so, subject to the following conditions:
23
+
24
+ The above copyright notice and this permission notice shall be included in
25
+ all copies or substantial portions of the Software.
26
+
27
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33
+ THE SOFTWARE.
34
+ License-File: LICENSE
35
+ Keywords: e-ink,planner,supernote,typst
36
+ Classifier: Development Status :: 4 - Beta
37
+ Classifier: License :: OSI Approved :: MIT License
38
+ Classifier: Programming Language :: Python
39
+ Classifier: Programming Language :: Python :: 3
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: Topic :: Printing
42
+ Requires-Python: >=3.12
43
+ Requires-Dist: pydantic>=2.13.4
44
+ Requires-Dist: questionary
45
+ Provides-Extra: dev
46
+ Requires-Dist: pytest>=8.0; extra == 'dev'
47
+ Description-Content-Type: text/markdown
48
+
49
+ # parch
50
+
51
+ **Parch** generates yearly planner PDFs for e-ink devices. Python port of Vitaliy Kudryk’s LYP: read a device profile, emit Typst, compile to PDF.
52
+
53
+ Formerly eink-planner.
54
+
55
+ This is a port of [Vitaliy Kudryk's LYP (latex-yearly-planner)](https://github.com/kudrykv/latex-yearly-planner/tree/alpha) ([fork point commit](https://github.com/kudrykv/latex-yearly-planner/commit/a59229770cfbf4a05b68a656dd70c02913a7df49), MIT, 2026). LYP generates a yearly planner by emitting **Typst**, then compiling that to **PDF**. This package keeps that architecture: Python reads a **TOML** device profile, walks calendar entities, and writes `index.typst` + `index.pdf`. It does **not** draw PDFs with reportlab/fpdf.
56
+
57
+ Default device is the **SuperNote Nomad** (A6 X2), MOS strip on the left. A Nomad MOS-right sibling, Kindle Scribe, and 158×210 MOS-left/MOS-right profiles are also shipped.
58
+
59
+ ## Install
60
+
61
+ Needs [uv](https://docs.astral.sh/uv/) and Python 3.12+.
62
+
63
+ ```shell
64
+ uv tool install parch
65
+ parch generate supernote-nomad
66
+ ```
67
+
68
+ `typst` is used to compile the PDF. If it is not on `PATH`, the compile step downloads the official Typst v0.15.1 binary for the current OS/arch into `.tools/typst` (`.tools/typst.exe` on Windows).
69
+
70
+ ## Generate
71
+
72
+ ```shell
73
+ # SuperNote Nomad 2026 (default profile, MOS-left) → ./out/index.pdf
74
+ uv run parch generate supernote-nomad
75
+
76
+ # SuperNote Nomad 2027 from the shipped 2026 profile (CLI overlay)
77
+ uv run parch generate supernote-nomad --year 2027
78
+
79
+ # SuperNote Nomad MOS-right → ./out/nomad-mos-right/index.pdf
80
+ uv run parch generate supernote-nomad-mos-right -w out/nomad-mos-right
81
+
82
+ # 158×210 MOS-left → ./out/mos-left/index.pdf
83
+ uv run parch generate 158x210-mos-left -w out/mos-left
84
+
85
+ # 158×210 MOS-left lined → ./out/mos-left-lined/index.pdf
86
+ uv run parch generate 158x210-mos-left-lined -w out/mos-left-lined
87
+
88
+ # 158×210 MOS-right → ./out/mos-right/index.pdf
89
+ uv run parch generate 158x210-mos-right -w out/mos-right
90
+
91
+ # Kindle Scribe → ./out/scribe/index.pdf
92
+ uv run parch generate kindle-scribe -w out/scribe
93
+ ```
94
+
95
+ Flags:
96
+
97
+ | Flag | Default | Meaning |
98
+ | --- | --- | --- |
99
+ | `-w` / `--workdir` | `./out` | Where `index.typst` and `index.pdf` are written |
100
+ | `-l` / `--locale` | `en` | Locale code |
101
+ | `-g` / `--with-ghostscript` | off | Optional PDF shrink via `gs` |
102
+ | `--debug` | off | Draw MOS debug strokes (not a config key) |
103
+ | `--year` | file year | Overlay planner year (dates and cover title; not a config key) |
104
+
105
+ `--year` also rewrites the cover title year when the old year is in the title.
106
+
107
+ Copy a shipped profile to start a new year or trim sections:
108
+
109
+ ```shell
110
+ uv run parch new --from supernote-nomad --year 2027 --yes -o mine.toml
111
+ ```
112
+
113
+ `parch new` without `--yes` asks for starting profile, year, sections, and output path. Locale stays `parch generate -l`.
114
+
115
+ A name in the top-level `sections = ["cover", …]` list is enabled, in that order. Comment a name out of `sections` to disable it. Details live under `[section.<name>]`. There is no `enabled = true` flag, and `debug` does not belong in the profile — use `parch generate --debug`. At least one section must remain.
116
+
117
+ ## Sample pages
118
+
119
+ 2026 from [`158x210-mos-left`](src/parch/data/configs/158x210-mos-left.toml). MOS strip on the left. This profile ships cover, Contents, the calendar sections, and the colophon (no projects, habits, review, tasks, or meetings). Previews are Typst SVGs at half scale. Regenerate with:
120
+
121
+ ```shell
122
+ uv run parch preview-svg 158x210-mos-left --samples
123
+ ```
124
+
125
+ | Section | Page |
126
+ | --- | --- |
127
+ | Cover | <img src="docs/samples/158x210-mos-left/cover.svg" alt="Cover" width="224" /> |
128
+ | Contents | <img src="docs/samples/158x210-mos-left/contents.svg" alt="Contents" width="224" /> |
129
+ | Annual | <img src="docs/samples/158x210-mos-left/annual.svg" alt="Annual" width="224" /> |
130
+ | Quarterly | <img src="docs/samples/158x210-mos-left/quarterly-q1.svg" alt="Quarterly" width="224" /> |
131
+ | Monthly | <img src="docs/samples/158x210-mos-left/monthly-jan.svg" alt="Monthly" width="224" /> |
132
+ | Weekly | <img src="docs/samples/158x210-mos-left/weekly-w01.svg" alt="Weekly" width="224" /> |
133
+ | Daily | <img src="docs/samples/158x210-mos-left/daily-jan1.svg" alt="Daily" width="224" /> |
134
+ | Daily notes | <img src="docs/samples/158x210-mos-left/notes-jan1.svg" alt="Daily notes" width="224" /> |
135
+ | Colophon | <img src="docs/samples/158x210-mos-left/colophon.svg" alt="Colophon" width="224" /> |
136
+
137
+ ## Device profiles
138
+
139
+ Sizes are 1:1 on glass at 300 PPI.
140
+
141
+ | Device | Pixels | Page (pt) | Page (mm) | Config |
142
+ | --- | --- | --- | --- | --- |
143
+ | SuperNote Nomad (A6 X2) | 1404×1872 | 336.96×449.28 | 118.87×158.5 | `supernote-nomad` |
144
+ | SuperNote Nomad MOS-right | 1404×1872 | 336.96×449.28 | 118.87×158.5 | `supernote-nomad-mos-right` |
145
+ | 158×210 MOS-left | — | 447.87×595.28 | 158×210 | `158x210-mos-left` |
146
+ | 158×210 MOS-left lined | — | 447.87×595.28 | 158×210 | `158x210-mos-left-lined` |
147
+ | 158×210 MOS-right | — | 447.87×595.28 | 158×210 | `158x210-mos-right` |
148
+ | Kindle Scribe | 1860×2480 | 446.4×595.2 | 157.48×209.97 | `kindle-scribe` |
149
+
150
+ Presets also live in `parch.devices`. The Nomad profile scales strokes, type, and gutters down slightly from the original 158×210 MOS-left gist so the MOS layout still fits the smaller page.
151
+
152
+ **MOS** is Months on the Side — the navigation style that places a vertical month menu on the side of the page (as opposed to a top breadcrumb trail).
153
+
154
+ Shipped configs keep the **MOS** (Months on the Side) layout: side menu on the physical left except 158×210 MOS-right and SuperNote Nomad MOS-right (physical right), reversed months/quarters, Monday week start, daily schedule 8–20, 5 priorities, 2 extra daily note pages, dotted scratch pad on most shipped configs (the 158×210 MOS-left lined sibling uses `scratch_pad = "lined"` under `[style]` with daily on-page notes still dotted). `pattern` is per notes area (dotted default; `lined` is the other option). MOS-left/MOS-right names are the physical MOS strip side (nav left / nav right), not which hand you write with. MOS-left is the right-handed writing layout (nav opposite the writing hand); MOS-right is the left-handed writing layout.
155
+
156
+ Device profiles and locale files are TOML. Config keys use underscores (`week_starts`, `side_menu`, `daily_notes`); filenames may still use hyphens (`supernote-nomad.toml`).
157
+
158
+ ## Development
159
+
160
+ ```shell
161
+ cd parch
162
+ uv sync
163
+ ```
164
+
165
+ ## Tests
166
+
167
+ ```shell
168
+ uv run pytest
169
+ ```
170
+
171
+ CI runs pytest and a Nomad `parch generate`. Visual design checks live in `tests/visual.py` and can be dropped with the tests that import them.
172
+
173
+ ## Layout of a generated planner
174
+
175
+ Enabled MOS (Months on the Side) sections, in order:
176
+
177
+ 1. Cover
178
+ 2. Annual (12 little calendars)
179
+ 3. Quarterly
180
+ 4. Monthly
181
+ 5. Weekly
182
+ 6. Daily (schedule + little calendar + priorities + notes)
183
+ 7. Daily notes (extra dotted pages)
184
+ 8. Projects (index of write-in names + one kanban board per project)
185
+ 9. Habits (index of 12 months + one habit-tracker grid per month)
186
+ 10. Review (index of weeks + one lined leftover-notes page per week; no MOS)
187
+ 11. Meetings (index of write-in names + one lined page per meeting)
188
+ 12. Colophon (quiet About page)
189
+
190
+ `[section.projects]` takes optional `pages` (default 16) and `card_rows` (default 5). Only Nomad ships projects enabled.
191
+ `[section.habits]` takes optional `habit_columns` (default 6) and `names` (default `[]`; first N header slots are typeset, the rest stay write-in). Enabled on both Nomad profiles.
192
+ `[section.review]` takes optional `weeks_per_page` (default 13). The week field is lined by default and can be `pattern = "dotted"`. Listing `review` without a table uses those defaults. Enabled on both Nomad profiles after Habits.
193
+ `[section.meetings]` takes optional `index_pages` (default 1). Enabled on Nomad after Review.
194
+
195
+ Internal PDF links use Typst `#padded_link` / `<label>` the same way LYP does. A link is only emitted when the target page exists; otherwise the cell stays plain text.
196
+
197
+ ## License
198
+
199
+ MIT. This is a port of Vitaliy Kudryk's LYP (MIT 2026). See `LICENSE`.
parch-0.1.0/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # parch
2
+
3
+ **Parch** generates yearly planner PDFs for e-ink devices. Python port of Vitaliy Kudryk’s LYP: read a device profile, emit Typst, compile to PDF.
4
+
5
+ Formerly eink-planner.
6
+
7
+ This is a port of [Vitaliy Kudryk's LYP (latex-yearly-planner)](https://github.com/kudrykv/latex-yearly-planner/tree/alpha) ([fork point commit](https://github.com/kudrykv/latex-yearly-planner/commit/a59229770cfbf4a05b68a656dd70c02913a7df49), MIT, 2026). LYP generates a yearly planner by emitting **Typst**, then compiling that to **PDF**. This package keeps that architecture: Python reads a **TOML** device profile, walks calendar entities, and writes `index.typst` + `index.pdf`. It does **not** draw PDFs with reportlab/fpdf.
8
+
9
+ Default device is the **SuperNote Nomad** (A6 X2), MOS strip on the left. A Nomad MOS-right sibling, Kindle Scribe, and 158×210 MOS-left/MOS-right profiles are also shipped.
10
+
11
+ ## Install
12
+
13
+ Needs [uv](https://docs.astral.sh/uv/) and Python 3.12+.
14
+
15
+ ```shell
16
+ uv tool install parch
17
+ parch generate supernote-nomad
18
+ ```
19
+
20
+ `typst` is used to compile the PDF. If it is not on `PATH`, the compile step downloads the official Typst v0.15.1 binary for the current OS/arch into `.tools/typst` (`.tools/typst.exe` on Windows).
21
+
22
+ ## Generate
23
+
24
+ ```shell
25
+ # SuperNote Nomad 2026 (default profile, MOS-left) → ./out/index.pdf
26
+ uv run parch generate supernote-nomad
27
+
28
+ # SuperNote Nomad 2027 from the shipped 2026 profile (CLI overlay)
29
+ uv run parch generate supernote-nomad --year 2027
30
+
31
+ # SuperNote Nomad MOS-right → ./out/nomad-mos-right/index.pdf
32
+ uv run parch generate supernote-nomad-mos-right -w out/nomad-mos-right
33
+
34
+ # 158×210 MOS-left → ./out/mos-left/index.pdf
35
+ uv run parch generate 158x210-mos-left -w out/mos-left
36
+
37
+ # 158×210 MOS-left lined → ./out/mos-left-lined/index.pdf
38
+ uv run parch generate 158x210-mos-left-lined -w out/mos-left-lined
39
+
40
+ # 158×210 MOS-right → ./out/mos-right/index.pdf
41
+ uv run parch generate 158x210-mos-right -w out/mos-right
42
+
43
+ # Kindle Scribe → ./out/scribe/index.pdf
44
+ uv run parch generate kindle-scribe -w out/scribe
45
+ ```
46
+
47
+ Flags:
48
+
49
+ | Flag | Default | Meaning |
50
+ | --- | --- | --- |
51
+ | `-w` / `--workdir` | `./out` | Where `index.typst` and `index.pdf` are written |
52
+ | `-l` / `--locale` | `en` | Locale code |
53
+ | `-g` / `--with-ghostscript` | off | Optional PDF shrink via `gs` |
54
+ | `--debug` | off | Draw MOS debug strokes (not a config key) |
55
+ | `--year` | file year | Overlay planner year (dates and cover title; not a config key) |
56
+
57
+ `--year` also rewrites the cover title year when the old year is in the title.
58
+
59
+ Copy a shipped profile to start a new year or trim sections:
60
+
61
+ ```shell
62
+ uv run parch new --from supernote-nomad --year 2027 --yes -o mine.toml
63
+ ```
64
+
65
+ `parch new` without `--yes` asks for starting profile, year, sections, and output path. Locale stays `parch generate -l`.
66
+
67
+ A name in the top-level `sections = ["cover", …]` list is enabled, in that order. Comment a name out of `sections` to disable it. Details live under `[section.<name>]`. There is no `enabled = true` flag, and `debug` does not belong in the profile — use `parch generate --debug`. At least one section must remain.
68
+
69
+ ## Sample pages
70
+
71
+ 2026 from [`158x210-mos-left`](src/parch/data/configs/158x210-mos-left.toml). MOS strip on the left. This profile ships cover, Contents, the calendar sections, and the colophon (no projects, habits, review, tasks, or meetings). Previews are Typst SVGs at half scale. Regenerate with:
72
+
73
+ ```shell
74
+ uv run parch preview-svg 158x210-mos-left --samples
75
+ ```
76
+
77
+ | Section | Page |
78
+ | --- | --- |
79
+ | Cover | <img src="docs/samples/158x210-mos-left/cover.svg" alt="Cover" width="224" /> |
80
+ | Contents | <img src="docs/samples/158x210-mos-left/contents.svg" alt="Contents" width="224" /> |
81
+ | Annual | <img src="docs/samples/158x210-mos-left/annual.svg" alt="Annual" width="224" /> |
82
+ | Quarterly | <img src="docs/samples/158x210-mos-left/quarterly-q1.svg" alt="Quarterly" width="224" /> |
83
+ | Monthly | <img src="docs/samples/158x210-mos-left/monthly-jan.svg" alt="Monthly" width="224" /> |
84
+ | Weekly | <img src="docs/samples/158x210-mos-left/weekly-w01.svg" alt="Weekly" width="224" /> |
85
+ | Daily | <img src="docs/samples/158x210-mos-left/daily-jan1.svg" alt="Daily" width="224" /> |
86
+ | Daily notes | <img src="docs/samples/158x210-mos-left/notes-jan1.svg" alt="Daily notes" width="224" /> |
87
+ | Colophon | <img src="docs/samples/158x210-mos-left/colophon.svg" alt="Colophon" width="224" /> |
88
+
89
+ ## Device profiles
90
+
91
+ Sizes are 1:1 on glass at 300 PPI.
92
+
93
+ | Device | Pixels | Page (pt) | Page (mm) | Config |
94
+ | --- | --- | --- | --- | --- |
95
+ | SuperNote Nomad (A6 X2) | 1404×1872 | 336.96×449.28 | 118.87×158.5 | `supernote-nomad` |
96
+ | SuperNote Nomad MOS-right | 1404×1872 | 336.96×449.28 | 118.87×158.5 | `supernote-nomad-mos-right` |
97
+ | 158×210 MOS-left | — | 447.87×595.28 | 158×210 | `158x210-mos-left` |
98
+ | 158×210 MOS-left lined | — | 447.87×595.28 | 158×210 | `158x210-mos-left-lined` |
99
+ | 158×210 MOS-right | — | 447.87×595.28 | 158×210 | `158x210-mos-right` |
100
+ | Kindle Scribe | 1860×2480 | 446.4×595.2 | 157.48×209.97 | `kindle-scribe` |
101
+
102
+ Presets also live in `parch.devices`. The Nomad profile scales strokes, type, and gutters down slightly from the original 158×210 MOS-left gist so the MOS layout still fits the smaller page.
103
+
104
+ **MOS** is Months on the Side — the navigation style that places a vertical month menu on the side of the page (as opposed to a top breadcrumb trail).
105
+
106
+ Shipped configs keep the **MOS** (Months on the Side) layout: side menu on the physical left except 158×210 MOS-right and SuperNote Nomad MOS-right (physical right), reversed months/quarters, Monday week start, daily schedule 8–20, 5 priorities, 2 extra daily note pages, dotted scratch pad on most shipped configs (the 158×210 MOS-left lined sibling uses `scratch_pad = "lined"` under `[style]` with daily on-page notes still dotted). `pattern` is per notes area (dotted default; `lined` is the other option). MOS-left/MOS-right names are the physical MOS strip side (nav left / nav right), not which hand you write with. MOS-left is the right-handed writing layout (nav opposite the writing hand); MOS-right is the left-handed writing layout.
107
+
108
+ Device profiles and locale files are TOML. Config keys use underscores (`week_starts`, `side_menu`, `daily_notes`); filenames may still use hyphens (`supernote-nomad.toml`).
109
+
110
+ ## Development
111
+
112
+ ```shell
113
+ cd parch
114
+ uv sync
115
+ ```
116
+
117
+ ## Tests
118
+
119
+ ```shell
120
+ uv run pytest
121
+ ```
122
+
123
+ CI runs pytest and a Nomad `parch generate`. Visual design checks live in `tests/visual.py` and can be dropped with the tests that import them.
124
+
125
+ ## Layout of a generated planner
126
+
127
+ Enabled MOS (Months on the Side) sections, in order:
128
+
129
+ 1. Cover
130
+ 2. Annual (12 little calendars)
131
+ 3. Quarterly
132
+ 4. Monthly
133
+ 5. Weekly
134
+ 6. Daily (schedule + little calendar + priorities + notes)
135
+ 7. Daily notes (extra dotted pages)
136
+ 8. Projects (index of write-in names + one kanban board per project)
137
+ 9. Habits (index of 12 months + one habit-tracker grid per month)
138
+ 10. Review (index of weeks + one lined leftover-notes page per week; no MOS)
139
+ 11. Meetings (index of write-in names + one lined page per meeting)
140
+ 12. Colophon (quiet About page)
141
+
142
+ `[section.projects]` takes optional `pages` (default 16) and `card_rows` (default 5). Only Nomad ships projects enabled.
143
+ `[section.habits]` takes optional `habit_columns` (default 6) and `names` (default `[]`; first N header slots are typeset, the rest stay write-in). Enabled on both Nomad profiles.
144
+ `[section.review]` takes optional `weeks_per_page` (default 13). The week field is lined by default and can be `pattern = "dotted"`. Listing `review` without a table uses those defaults. Enabled on both Nomad profiles after Habits.
145
+ `[section.meetings]` takes optional `index_pages` (default 1). Enabled on Nomad after Review.
146
+
147
+ Internal PDF links use Typst `#padded_link` / `<label>` the same way LYP does. A link is only emitted when the target page exists; otherwise the cell stays plain text.
148
+
149
+ ## License
150
+
151
+ MIT. This is a port of Vitaliy Kudryk's LYP (MIT 2026). See `LICENSE`.