131 lines
3.9 KiB
Python
131 lines
3.9 KiB
Python
import randomname
|
|
|
|
from textual import on, work
|
|
from textual.app import App, ComposeResult
|
|
from textual.events import Click
|
|
from textual.screen import Screen
|
|
from textual.message import Message
|
|
from textual.css.query import NoMatches
|
|
from textual.reactive import reactive
|
|
from textual.containers import (
|
|
Container,
|
|
Center,
|
|
Horizontal,
|
|
VerticalScroll
|
|
)
|
|
from textual.widgets import (
|
|
Button,
|
|
Footer,
|
|
Input,
|
|
Label,
|
|
Rule,
|
|
Static
|
|
)
|
|
|
|
class CardSelected(Message):
|
|
def __init__(self, card_id: int) -> None:
|
|
super().__init__()
|
|
self.card_id = card_id
|
|
|
|
|
|
class RecipeCard(Static):
|
|
visible_status: bool = reactive(True)
|
|
|
|
def __init__(self, recipe_data: dict = {}):
|
|
super().__init__()
|
|
self.recipe_name = recipe_data.get('recipe_name', "<no name>")
|
|
self.card_id = recipe_data.get('card_id', 0)
|
|
self.border_title = f"{self.recipe_name} - {self.card_id}"
|
|
|
|
try:
|
|
self.id = f"recipe-{self.card_id}"
|
|
except:
|
|
pass
|
|
|
|
def compose(self) -> ComposeResult:
|
|
yield Label("Cook Time: 10m", classes="card")
|
|
yield Rule(line_style="solid", classes="rule-color")
|
|
yield Label("Description", classes="recipecard-label")
|
|
yield Static(
|
|
"This dish is full of nonsense and this is a long text label",
|
|
classes="card"
|
|
)
|
|
|
|
def on_click(self, event: Click) -> None:
|
|
self.post_message(CardSelected(self.id))
|
|
|
|
def watch_visible_status(self, visible: bool) -> None:
|
|
if visible:
|
|
print(f"Card {self.id} is visible!")
|
|
self.remove_class('invisible')
|
|
else:
|
|
print(f"Card {self.id} is invisible!")
|
|
self.add_class('invisible')
|
|
|
|
|
|
class SearchPageScreen(Screen):
|
|
def __init__(self) -> None:
|
|
super().__init__()
|
|
self.selected_card_id = None
|
|
|
|
def compose(self) -> ComposeResult:
|
|
with Container(id="background-container"):
|
|
with Center(id="header"):
|
|
yield Horizontal(
|
|
Button("Back", id="button-go-back"),
|
|
Input(placeholder="Search a recipe..", id="search-input"),
|
|
Button("Search Recipes", id="enter-button"),
|
|
id="header-components"
|
|
)
|
|
with VerticalScroll(id="recipe-list"):
|
|
for x in range(1, 21):
|
|
yield RecipeCard(
|
|
recipe_data={
|
|
"recipe_name": randomname.generate(sep=" "),
|
|
"card_id": x
|
|
}
|
|
)
|
|
yield Footer()
|
|
|
|
@on(CardSelected)
|
|
def card_selected(self, message: CardSelected) -> None:
|
|
card_id = message.card_id
|
|
card = self.query_one(f"#{card_id}", RecipeCard)
|
|
if card_id == self.selected_card_id:
|
|
card.remove_class("recipe-highlighted")
|
|
self.selected_card_id = None
|
|
else:
|
|
try:
|
|
old_card = self.query_one(f"#{self.selected_card_id}", RecipeCard)
|
|
old_card.remove_class("recipe-highlighted")
|
|
except NoMatches:
|
|
print(f"Card not fount {self.selected_card_id}")
|
|
self.selected_card_id = card_id
|
|
card.add_class('recipe-highlighted')
|
|
|
|
@on(Input.Changed)
|
|
def filter_cards(self, event: Input.Changed) -> None:
|
|
query = event.value.strip().lower()
|
|
for card in self.query(RecipeCard):
|
|
if query in card.recipe_name:
|
|
card.visible_status = True
|
|
else:
|
|
card.visible_status = False
|
|
self.refresh()
|
|
|
|
|
|
class CookbookApp(App):
|
|
CSS_PATH = "cookbook.css"
|
|
|
|
def __init__(self) -> None:
|
|
super().__init__()
|
|
self.theme = "monokai"
|
|
|
|
def on_mount(self) -> None:
|
|
self.push_screen(SearchPageScreen())
|
|
|
|
if __name__ == "__main__":
|
|
app = CookbookApp()
|
|
app.run()
|
|
|