Replace content CLI with Textual TUI
This commit is contained in:
1 parent
0d58ddd430
commit
737700a9a8
28 files changed
+2403
-167
No files matched your search
@@ -0,0 +1,68 @@
|
||||
from rich.text import Text
|
||||
from textual import on
|
||||
from textual.app import ComposeResult
|
||||
from textual.binding import Binding
|
||||
from textual.containers import Vertical
|
||||
from textual.screen import ModalScreen
|
||||
from textual.widgets import Input, Label, OptionList
|
||||
from textual.widgets.option_list import Option
|
||||
|
||||
import static_images
|
||||
|
||||
|
||||
class ImagePicker(ModalScreen[str | None]):
|
||||
BINDINGS = [
|
||||
Binding("escape", "cancel", "Cancel"),
|
||||
Binding("down", "focus_list", "List", show=False),
|
||||
]
|
||||
|
||||
def __init__(self, current: str = "", start_filter: str = ""):
|
||||
super().__init__()
|
||||
self.current = current
|
||||
self.start_filter = start_filter
|
||||
self.images: list[dict] = []
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with Vertical(classes="dialog picker"):
|
||||
yield Label("Pick an image from static/", classes="dialog-title")
|
||||
yield Input(value=self.start_filter, placeholder="Type to filter, Enter to pick", id="image-filter")
|
||||
yield OptionList(id="image-list")
|
||||
yield Label("", id="image-count", classes="field-label")
|
||||
|
||||
def on_mount(self):
|
||||
self.images = static_images.list_images()
|
||||
self.show_images(self.start_filter)
|
||||
|
||||
def show_images(self, text: str):
|
||||
query = text.strip().lower()
|
||||
matches = [image for image in self.images if query in image["path"].lower()]
|
||||
option_list = self.query_one(OptionList)
|
||||
option_list.clear_options()
|
||||
option_list.add_options(
|
||||
Option(Text.assemble(image["path"], (" " + static_images.format_size(image["size"]), "dim")), id=image["path"])
|
||||
for image in matches
|
||||
)
|
||||
current_index = next((index for index, image in enumerate(matches) if image["path"] == self.current), 0)
|
||||
if matches:
|
||||
option_list.highlighted = current_index
|
||||
self.query_one("#image-count", Label).update(f"{len(matches)} of {len(self.images)} images")
|
||||
|
||||
@on(Input.Changed, "#image-filter")
|
||||
def filter_changed(self, event: Input.Changed):
|
||||
self.show_images(event.value)
|
||||
|
||||
@on(Input.Submitted, "#image-filter")
|
||||
def pick_highlighted(self):
|
||||
option_list = self.query_one(OptionList)
|
||||
if option_list.highlighted is not None and option_list.option_count:
|
||||
self.dismiss(option_list.get_option_at_index(option_list.highlighted).id)
|
||||
|
||||
@on(OptionList.OptionSelected)
|
||||
def pick_option(self, event: OptionList.OptionSelected):
|
||||
self.dismiss(event.option.id)
|
||||
|
||||
def action_focus_list(self):
|
||||
self.query_one(OptionList).focus()
|
||||
|
||||
def action_cancel(self):
|
||||
self.dismiss(None)
|
||||
Reference in new issue
Block a user