1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
from itertools import cycle
from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.containers import Horizontal, Vertical
from textual.widgets import Footer, Header, Input, Label, SelectionList
class TodoList(App[None]):
CSS = """
Screen {
align: center middle;
hatch: right $foreground 10%;
}
#content {
height: auto;
width: 40;
padding: 1 2;
}
#header {
height: 1;
width: auto;
margin-bottom: 1;
}
.title {
text-style: bold;
padding: 0 1;
width: 1fr;
}
#overdue {
color: $text-error;
background: $error-muted;
padding: 0 1;
width: auto;
}
#done {
color: $text-success;
background: $success-muted;
padding: 0 1;
margin: 0 1;
}
#footer {
height: auto;
margin-bottom: 2;
}
#history-header {
height: 1;
width: auto;
}
#history-done {
width: auto;
padding: 0 1;
margin: 0 1;
background: $primary-muted;
color: $text-primary;
}
"""
BINDINGS = [Binding("ctrl+t", "cycle_theme", "Cycle theme")]
THEMES = cycle(
["nord", "gruvbox", "tokyo-night", "textual-dark", "solarized-light"]
)
def compose(self) -> ComposeResult:
yield Header()
with Vertical(id="content"):
with Horizontal(id="header"):
yield Label("Today", classes="title")
yield Label("1 overdue", id="overdue")
yield Label("1 done", id="done")
yield SelectionList(
("Buy milk", 0),
("Buy bread", 1),
("Go and vote", 2, True),
("Return package", 3),
id="todo-list",
)
with Horizontal(id="footer"):
yield Input(placeholder="Add a task")
with Horizontal(id="history-header"):
yield Label("History", classes="title")
yield Label("4 items", id="history-done")
yield Footer()
def on_mount(self) -> None:
self.action_cycle_theme()
def action_cycle_theme(self) -> None:
self.theme = next(self.THEMES)
app = TodoList()
if __name__ == "__main__":
app.run()
|