mirror of https://github.com/JoshKarpel/spiel
Expand demo deck (#3)
* upgrade demo deck, and make some incidental improvements along the way * bump rich versionpull/5/head
parent
52de31de1c
commit
3b6cb78cfe
@ -1,89 +1,189 @@
|
||||
import inspect
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
from textwrap import dedent
|
||||
|
||||
from rich.align import Align
|
||||
from rich.console import ConsoleRenderable
|
||||
from rich.console import RenderGroup
|
||||
from rich.layout import Layout
|
||||
from rich.markdown import Markdown
|
||||
from rich.panel import Panel
|
||||
from rich.style import Style
|
||||
from rich.syntax import Syntax
|
||||
from rich.text import Text
|
||||
|
||||
from spiel import Deck, Slide
|
||||
from spiel import Deck, Slide, __version__
|
||||
|
||||
DECK = Deck(name="Spiel Demo Deck")
|
||||
SPIEL = "[Spiel](https://github.com/JoshKarpel/spiel)"
|
||||
RICH = "[Rich](https://rich.readthedocs.io/)"
|
||||
|
||||
left_markup = """\
|
||||
## What is Spiel?
|
||||
|
||||
[Spiel](https://github.com/JoshKarpel/spiel) is a framework for building slide decks in Python.
|
||||
def what():
|
||||
left_markup = dedent(
|
||||
f"""\
|
||||
## What is Spiel?
|
||||
|
||||
Spiel uses [Rich](https://rich.readthedocs.io/) to render slide content.
|
||||
"""
|
||||
{SPIEL} is a framework for building slide decks in Python.
|
||||
|
||||
right_markup = """\
|
||||
## Why Spiel?
|
||||
Spiel uses {RICH} to render slide content.
|
||||
|
||||
It's fun!
|
||||
Anything you can display with Rich, you can display with Spiel!
|
||||
"""
|
||||
)
|
||||
|
||||
It's weird!
|
||||
"""
|
||||
right_markup = dedent(
|
||||
"""\
|
||||
## Why use Spiel?
|
||||
|
||||
layout = Layout()
|
||||
left = Layout(
|
||||
Markdown(
|
||||
left_markup,
|
||||
justify="center",
|
||||
),
|
||||
ratio=2,
|
||||
)
|
||||
buffer = Layout(" ")
|
||||
right = Layout(
|
||||
Markdown(
|
||||
right_markup,
|
||||
justify="center",
|
||||
),
|
||||
ratio=2,
|
||||
)
|
||||
layout.split_row(left, buffer, right)
|
||||
It's fun!
|
||||
|
||||
DECK.add_slide(
|
||||
Slide(
|
||||
content=layout,
|
||||
It's weird!
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class Now:
|
||||
def __rich__(self) -> ConsoleRenderable:
|
||||
return Align(
|
||||
Text(
|
||||
f"Right now, at {datetime.now()}!",
|
||||
style=Style(color="bright_cyan", bold=True, italic=True),
|
||||
r = 3
|
||||
root = Layout()
|
||||
root.split_row(
|
||||
Layout(
|
||||
Markdown(
|
||||
left_markup,
|
||||
justify="center",
|
||||
),
|
||||
ratio=r,
|
||||
),
|
||||
Layout(" "),
|
||||
Layout(
|
||||
Markdown(
|
||||
right_markup,
|
||||
justify="center",
|
||||
),
|
||||
align="center",
|
||||
)
|
||||
ratio=r,
|
||||
),
|
||||
)
|
||||
|
||||
return Slide(root, title="What is Spiel?")
|
||||
|
||||
|
||||
DECK.add_slide(
|
||||
Slide(
|
||||
content=Now(),
|
||||
def code():
|
||||
markup = dedent(
|
||||
f"""\
|
||||
## Decks are made of Slides
|
||||
|
||||
Here's the code for `Deck` and `Slide`!
|
||||
|
||||
The source code is pulled directly from the definitions via [`inspect.getsource`](https://docs.python.org/3/library/inspect.html#inspect.getsource).
|
||||
|
||||
(Because {RICH} supports syntax highlighting, so does {SPIEL}!)
|
||||
"""
|
||||
)
|
||||
root = Layout()
|
||||
upper = Layout(Markdown(markup, justify="center"), size=len(markup.split("\n")) + 1)
|
||||
lower = Layout()
|
||||
root.split_column(upper, lower)
|
||||
|
||||
lower.split_row(
|
||||
Layout(
|
||||
Syntax(
|
||||
inspect.getsource(Deck),
|
||||
lexer_name="python",
|
||||
),
|
||||
),
|
||||
Layout(
|
||||
Syntax(
|
||||
inspect.getsource(Slide),
|
||||
lexer_name="python",
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
return Slide(root, title="Decks and Slides")
|
||||
|
||||
class Where:
|
||||
def __rich__(self) -> ConsoleRenderable:
|
||||
return Align(
|
||||
Text(
|
||||
f"Right here, at {socket.gethostname()}!",
|
||||
style=Style(color="bright_cyan", bold=True, italic=True),
|
||||
|
||||
def dynamic():
|
||||
tmp_dir = tempfile.gettempdir()
|
||||
width = shutil.get_terminal_size().columns
|
||||
return Slide(
|
||||
RenderGroup(
|
||||
Align(
|
||||
Text(
|
||||
f"Your slides can have very dynamic content, like this!",
|
||||
style=Style(color="bright_magenta", bold=True, italic=True),
|
||||
),
|
||||
align="center",
|
||||
),
|
||||
Align(
|
||||
Panel(
|
||||
Text(
|
||||
f"The time on this computer, {socket.gethostname()}, is {datetime.now()}",
|
||||
style=Style(color="bright_cyan", bold=True, italic=True),
|
||||
justify="center",
|
||||
)
|
||||
),
|
||||
align="center",
|
||||
),
|
||||
Align(
|
||||
Panel(
|
||||
Text(
|
||||
f"Your terminal is {width} characters wide."
|
||||
if width > 80
|
||||
else f"Your terminal is only {width} characters wide! Get a bigger monitor!",
|
||||
style=Style(color="green1" if width > 80 else "red"),
|
||||
justify="center",
|
||||
)
|
||||
),
|
||||
align="center",
|
||||
),
|
||||
Align(
|
||||
Panel(
|
||||
Text(
|
||||
f"There are {len(os.listdir(tmp_dir))} entries under {tmp_dir} right now.",
|
||||
style=Style(color="yellow"),
|
||||
justify="center",
|
||||
)
|
||||
),
|
||||
align="center",
|
||||
),
|
||||
align="right",
|
||||
)
|
||||
),
|
||||
title="Dynamic Content",
|
||||
)
|
||||
|
||||
|
||||
def grid():
|
||||
markup = dedent(
|
||||
"""\
|
||||
## Multiple Views
|
||||
|
||||
DECK.add_slide(
|
||||
Slide(
|
||||
content=Where(),
|
||||
Try pressing 'd' to go into "deck" view.
|
||||
Press 's' to go back to "slide" view.
|
||||
"""
|
||||
)
|
||||
return Slide(Markdown(markup, justify="center"), title="Views")
|
||||
|
||||
|
||||
def watch():
|
||||
markup = dedent(
|
||||
f"""\
|
||||
## Developing a Deck
|
||||
|
||||
{SPIEL} can reload your deck as you edit it if you add the `--watch` option to `display`:
|
||||
|
||||
`$ spiel display examples/demo.py --watch`
|
||||
|
||||
If you're on a system without inotify support (e.g., Windows Subsystem for Linux), you may need to use the `--poll` option instead.
|
||||
|
||||
When you're ready to present your deck for real, just drop the `--watch` option.
|
||||
"""
|
||||
)
|
||||
return Slide(Markdown(markup, justify="center"), title="Watch Mode")
|
||||
|
||||
|
||||
DECK = Deck(name=f"Spiel Demo Deck (v{__version__})").add_slides(
|
||||
what(),
|
||||
code(),
|
||||
dynamic,
|
||||
grid(),
|
||||
watch(),
|
||||
)
|
||||
|
@ -1,30 +1,49 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List, Union
|
||||
from typing import Callable, List, Union
|
||||
|
||||
from rich.console import ConsoleRenderable, RichCast
|
||||
from rich.text import Text
|
||||
|
||||
Renderable = Union[RichCast, ConsoleRenderable]
|
||||
Contentlike = Union[Renderable, Callable[[], Renderable]]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Slide:
|
||||
content: Union[RichCast, ConsoleRenderable] = field(default_factory=Text)
|
||||
content: Contentlike = field(default_factory=Text)
|
||||
title: str = ""
|
||||
|
||||
def render(self) -> Renderable:
|
||||
if callable(self.content):
|
||||
return self.content()
|
||||
else:
|
||||
return self.content
|
||||
|
||||
def __call__(self) -> Slide:
|
||||
return self
|
||||
|
||||
|
||||
Slidelike = Union[Slide, Callable[[], Slide]]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Deck:
|
||||
name: str
|
||||
slides: List[Slide] = field(default_factory=list)
|
||||
_slides: List[Slidelike] = field(default_factory=list)
|
||||
|
||||
@property
|
||||
def slides(self) -> List[Slide]:
|
||||
return [slide() for slide in self._slides]
|
||||
|
||||
def __getitem__(self, idx: int) -> Slide:
|
||||
return self.slides[idx]
|
||||
return self.slides[idx]()
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.slides)
|
||||
|
||||
def add_slide(self, slide: Slide) -> Deck:
|
||||
self.slides.append(slide)
|
||||
def add_slides(self, *slides: Slidelike) -> Deck:
|
||||
self._slides.extend(slides)
|
||||
|
||||
return self
|
||||
|
Loading…
Reference in New Issue