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 +21 -0
- termdeck-0.1.0/PKG-INFO +94 -0
- termdeck-0.1.0/README.md +70 -0
- termdeck-0.1.0/pyproject.toml +38 -0
- termdeck-0.1.0/setup.cfg +4 -0
- termdeck-0.1.0/termdeck/__init__.py +1 -0
- termdeck-0.1.0/termdeck/__main__.py +3 -0
- termdeck-0.1.0/termdeck/app.py +43 -0
- termdeck-0.1.0/termdeck/deck.py +67 -0
- termdeck-0.1.0/termdeck/sample/p01_intro.md +5 -0
- termdeck-0.1.0/termdeck/sample/p02_slides.md +6 -0
- termdeck-0.1.0/termdeck/styles/default.tcss +3 -0
- termdeck-0.1.0/termdeck.egg-info/PKG-INFO +94 -0
- termdeck-0.1.0/termdeck.egg-info/SOURCES.txt +16 -0
- termdeck-0.1.0/termdeck.egg-info/dependency_links.txt +1 -0
- termdeck-0.1.0/termdeck.egg-info/entry_points.txt +2 -0
- termdeck-0.1.0/termdeck.egg-info/requires.txt +10 -0
- termdeck-0.1.0/termdeck.egg-info/top_level.txt +1 -0
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.
|
termdeck-0.1.0/PKG-INFO
ADDED
|
@@ -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
|
termdeck-0.1.0/README.md
ADDED
|
@@ -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/*"]
|
termdeck-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
@@ -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,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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
termdeck
|