termdeck 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.
termdeck-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 termdeck contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,94 @@
1
+ Metadata-Version: 2.4
2
+ Name: termdeck
3
+ Version: 0.1.0
4
+ Summary: Terminal presentations, written in Markdown or Python
5
+ License: MIT
6
+ Keywords: presentation,slides,terminal,textual,markdown
7
+ Classifier: Environment :: Console
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Topic :: Multimedia :: Graphics :: Presentation
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: textual>=0.84
16
+ Provides-Extra: music
17
+ Requires-Dist: musicpy; extra == "music"
18
+ Requires-Dist: pygame; extra == "music"
19
+ Requires-Dist: mido-fix; extra == "music"
20
+ Provides-Extra: dev
21
+ Requires-Dist: build; extra == "dev"
22
+ Requires-Dist: twine; extra == "dev"
23
+ Dynamic: license-file
24
+
25
+ # TermDeck
26
+
27
+ Terminal presentations, written in Markdown or Python. Built on [Textual](https://github.com/Textualize/textual).
28
+
29
+ Each file in a deck folder is one slide. Navigate with the arrow keys.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ pip install termdeck
35
+ ```
36
+
37
+ Optional extras:
38
+
39
+ ```bash
40
+ pip install "termdeck[music]" # interactive music-pad slides
41
+ ```
42
+
43
+ ## Usage
44
+
45
+ ```bash
46
+ termdeck # play the bundled sample deck
47
+ termdeck ./my-deck # play your own deck
48
+ python -m termdeck # same thing
49
+ ```
50
+
51
+ Navigate with **← / →** arrow keys; quit with **Ctrl+C**.
52
+
53
+ ## Writing a deck
54
+
55
+ A deck is a folder of slide files. Files are sorted by name.
56
+
57
+ ### Markdown slides
58
+
59
+ ```markdown
60
+ # My title
61
+
62
+ - a bullet
63
+ - another bullet
64
+ ```
65
+
66
+ ### Python slides
67
+
68
+ A Python slide is a [Textual `Screen`](https://textual.textualize.io/api/screen/). It must expose a `Slide` class:
69
+
70
+ ```python
71
+ from textual.app import ComposeResult
72
+ from textual.screen import Screen
73
+ from textual.widgets import Button
74
+
75
+ class Slide(Screen):
76
+ def compose(self) -> ComposeResult:
77
+ yield Button("Hello")
78
+ ```
79
+
80
+ The screen's widgets are styled by `styles/default.tcss`, which you can override in
81
+ your deck if you want. All Textual functionality is available for rich,
82
+ interactive slides.
83
+
84
+ ## Development
85
+
86
+ ```bash
87
+ pip install -e ".[dev]"
88
+ python test.py
89
+ python -m build
90
+ ```
91
+
92
+ ## License
93
+
94
+ MIT
@@ -0,0 +1,70 @@
1
+ # TermDeck
2
+
3
+ Terminal presentations, written in Markdown or Python. Built on [Textual](https://github.com/Textualize/textual).
4
+
5
+ Each file in a deck folder is one slide. Navigate with the arrow keys.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install termdeck
11
+ ```
12
+
13
+ Optional extras:
14
+
15
+ ```bash
16
+ pip install "termdeck[music]" # interactive music-pad slides
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```bash
22
+ termdeck # play the bundled sample deck
23
+ termdeck ./my-deck # play your own deck
24
+ python -m termdeck # same thing
25
+ ```
26
+
27
+ Navigate with **← / →** arrow keys; quit with **Ctrl+C**.
28
+
29
+ ## Writing a deck
30
+
31
+ A deck is a folder of slide files. Files are sorted by name.
32
+
33
+ ### Markdown slides
34
+
35
+ ```markdown
36
+ # My title
37
+
38
+ - a bullet
39
+ - another bullet
40
+ ```
41
+
42
+ ### Python slides
43
+
44
+ A Python slide is a [Textual `Screen`](https://textual.textualize.io/api/screen/). It must expose a `Slide` class:
45
+
46
+ ```python
47
+ from textual.app import ComposeResult
48
+ from textual.screen import Screen
49
+ from textual.widgets import Button
50
+
51
+ class Slide(Screen):
52
+ def compose(self) -> ComposeResult:
53
+ yield Button("Hello")
54
+ ```
55
+
56
+ The screen's widgets are styled by `styles/default.tcss`, which you can override in
57
+ your deck if you want. All Textual functionality is available for rich,
58
+ interactive slides.
59
+
60
+ ## Development
61
+
62
+ ```bash
63
+ pip install -e ".[dev]"
64
+ python test.py
65
+ python -m build
66
+ ```
67
+
68
+ ## License
69
+
70
+ MIT
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "termdeck"
7
+ dynamic = ["version"]
8
+ description = "Terminal presentations, written in Markdown or Python"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.8"
12
+ keywords = ["presentation", "slides", "terminal", "textual", "markdown"]
13
+ classifiers = [
14
+ "Environment :: Console",
15
+ "Intended Audience :: Developers",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Programming Language :: Python :: 3",
18
+ "Topic :: Multimedia :: Graphics :: Presentation",
19
+ ]
20
+ dependencies = [
21
+ "textual>=0.84",
22
+ ]
23
+
24
+ [project.optional-dependencies]
25
+ music = ["musicpy", "pygame", "mido-fix"]
26
+ dev = ["build", "twine"]
27
+
28
+ [project.scripts]
29
+ termdeck = "termdeck.deck:main"
30
+
31
+ [tool.setuptools]
32
+ packages = ["termdeck"]
33
+
34
+ [tool.setuptools.dynamic]
35
+ version = { attr = "termdeck.__version__" }
36
+
37
+ [tool.setuptools.package-data]
38
+ termdeck = ["styles/*.tcss", "sample/*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,3 @@
1
+ from termdeck.deck import main
2
+
3
+ main()
@@ -0,0 +1,43 @@
1
+ from pathlib import Path
2
+
3
+ from textual import events
4
+ from textual.app import App
5
+ from textual.widgets import Footer, Header
6
+
7
+ from termdeck.deck import load_deck
8
+
9
+
10
+ class TermDeck(App):
11
+ """A terminal presentation app: arrow keys walk through a deck of slides."""
12
+
13
+ title = "TermDeck"
14
+ CSS_PATH = str(Path(__file__).parent / "styles" / "default.tcss")
15
+
16
+ def __init__(self, deck_dir: Path, *args, **kwargs):
17
+ super().__init__(*args, **kwargs)
18
+ self.slide_number = 0
19
+ self.names = [name for name, _ in load_deck(deck_dir)]
20
+ for name, cls in load_deck(deck_dir):
21
+ self.install_screen(cls, name)
22
+
23
+ def on_key(self, event: events.Key) -> None:
24
+ names = self.names
25
+ if not names:
26
+ return
27
+
28
+ if event.key == "right" and self.slide_number < len(names) - 1:
29
+ self.slide_number += 1
30
+ elif event.key == "left" and self.slide_number > 0:
31
+ self.slide_number -= 1
32
+ else:
33
+ return
34
+
35
+ self.push_screen(names[self.slide_number])
36
+
37
+ def compose(self):
38
+ yield Header()
39
+ yield Footer()
40
+
41
+
42
+ if __name__ == "__main__":
43
+ TermDeck(Path("slides")).run()
@@ -0,0 +1,67 @@
1
+ import importlib.util
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ from textual.screen import Screen
6
+ from textual.widgets import Markdown
7
+
8
+ SLIDE_EXTS = (".md", ".MD", ".py")
9
+
10
+
11
+ def load_slide(path: Path) -> type[Screen]:
12
+ """Load a single slide file (markdown or python Textual screen) as a Screen."""
13
+ path = Path(path)
14
+ if path.suffix in (".md", ".MD"):
15
+ return _markdown_slide(path.read_text())
16
+ if path.suffix == ".py":
17
+ return _python_slide(path)
18
+ raise ValueError(f"Unsupported slide type: {path.suffix}")
19
+
20
+
21
+ def load_deck(directory: Path) -> list[tuple[str, type[Screen]]]:
22
+ """Load all slides in a directory, sorted by filename."""
23
+ slides = []
24
+ for path in sorted(Path(directory).iterdir()):
25
+ if path.name == "__init__.py":
26
+ continue
27
+ if path.suffix not in SLIDE_EXTS:
28
+ continue
29
+ slides.append((path.name, load_slide(path)))
30
+ return slides
31
+
32
+
33
+ def _markdown_slide(content: str) -> type[Screen]:
34
+ class Slide(Screen):
35
+ def compose(self):
36
+ yield Markdown(content, id="markdown")
37
+
38
+ return Slide
39
+
40
+
41
+ def _python_slide(path: Path) -> type[Screen]:
42
+ spec = importlib.util.spec_from_file_location(f"termdeck_slide_{path.stem}", path)
43
+ module = importlib.util.module_from_spec(spec)
44
+ spec.loader.exec_module(module)
45
+ return module.Slide
46
+
47
+
48
+ def main() -> None:
49
+ if len(sys.argv) > 1:
50
+ deck_dir = Path(sys.argv[1])
51
+ else:
52
+ deck_dir = Path(__file__).parent / "sample"
53
+
54
+ if not deck_dir.is_dir():
55
+ sys.exit(f"error: not a directory: {deck_dir}")
56
+
57
+ slides = load_deck(deck_dir)
58
+ if not slides:
59
+ sys.exit(f"error: no slides (.md/.py) found in {deck_dir}")
60
+
61
+ from termdeck.app import TermDeck
62
+
63
+ TermDeck(deck_dir).run()
64
+
65
+
66
+ if __name__ == "__main__":
67
+ main()
@@ -0,0 +1,5 @@
1
+ # TermDeck
2
+
3
+ Terminal presentations, written in Markdown or Python.
4
+
5
+ Navigate with the arrow keys.
@@ -0,0 +1,6 @@
1
+ # Writing slides
2
+
3
+ Each file in your deck directory is one slide.
4
+
5
+ - `something.md` renders as Markdown
6
+ - `something.py` defines a Textual screen (must expose a `Slide` class)
@@ -0,0 +1,3 @@
1
+ #markdown {
2
+ margin: 0 20;
3
+ }
@@ -0,0 +1,94 @@
1
+ Metadata-Version: 2.4
2
+ Name: termdeck
3
+ Version: 0.1.0
4
+ Summary: Terminal presentations, written in Markdown or Python
5
+ License: MIT
6
+ Keywords: presentation,slides,terminal,textual,markdown
7
+ Classifier: Environment :: Console
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Topic :: Multimedia :: Graphics :: Presentation
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: textual>=0.84
16
+ Provides-Extra: music
17
+ Requires-Dist: musicpy; extra == "music"
18
+ Requires-Dist: pygame; extra == "music"
19
+ Requires-Dist: mido-fix; extra == "music"
20
+ Provides-Extra: dev
21
+ Requires-Dist: build; extra == "dev"
22
+ Requires-Dist: twine; extra == "dev"
23
+ Dynamic: license-file
24
+
25
+ # TermDeck
26
+
27
+ Terminal presentations, written in Markdown or Python. Built on [Textual](https://github.com/Textualize/textual).
28
+
29
+ Each file in a deck folder is one slide. Navigate with the arrow keys.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ pip install termdeck
35
+ ```
36
+
37
+ Optional extras:
38
+
39
+ ```bash
40
+ pip install "termdeck[music]" # interactive music-pad slides
41
+ ```
42
+
43
+ ## Usage
44
+
45
+ ```bash
46
+ termdeck # play the bundled sample deck
47
+ termdeck ./my-deck # play your own deck
48
+ python -m termdeck # same thing
49
+ ```
50
+
51
+ Navigate with **← / →** arrow keys; quit with **Ctrl+C**.
52
+
53
+ ## Writing a deck
54
+
55
+ A deck is a folder of slide files. Files are sorted by name.
56
+
57
+ ### Markdown slides
58
+
59
+ ```markdown
60
+ # My title
61
+
62
+ - a bullet
63
+ - another bullet
64
+ ```
65
+
66
+ ### Python slides
67
+
68
+ A Python slide is a [Textual `Screen`](https://textual.textualize.io/api/screen/). It must expose a `Slide` class:
69
+
70
+ ```python
71
+ from textual.app import ComposeResult
72
+ from textual.screen import Screen
73
+ from textual.widgets import Button
74
+
75
+ class Slide(Screen):
76
+ def compose(self) -> ComposeResult:
77
+ yield Button("Hello")
78
+ ```
79
+
80
+ The screen's widgets are styled by `styles/default.tcss`, which you can override in
81
+ your deck if you want. All Textual functionality is available for rich,
82
+ interactive slides.
83
+
84
+ ## Development
85
+
86
+ ```bash
87
+ pip install -e ".[dev]"
88
+ python test.py
89
+ python -m build
90
+ ```
91
+
92
+ ## License
93
+
94
+ MIT
@@ -0,0 +1,16 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ termdeck/__init__.py
5
+ termdeck/__main__.py
6
+ termdeck/app.py
7
+ termdeck/deck.py
8
+ termdeck.egg-info/PKG-INFO
9
+ termdeck.egg-info/SOURCES.txt
10
+ termdeck.egg-info/dependency_links.txt
11
+ termdeck.egg-info/entry_points.txt
12
+ termdeck.egg-info/requires.txt
13
+ termdeck.egg-info/top_level.txt
14
+ termdeck/sample/p01_intro.md
15
+ termdeck/sample/p02_slides.md
16
+ termdeck/styles/default.tcss
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ termdeck = termdeck.deck:main
@@ -0,0 +1,10 @@
1
+ textual>=0.84
2
+
3
+ [dev]
4
+ build
5
+ twine
6
+
7
+ [music]
8
+ musicpy
9
+ pygame
10
+ mido-fix
@@ -0,0 +1 @@
1
+ termdeck