diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app.py b/app.py new file mode 100644 index 0000000..e9373fa --- /dev/null +++ b/app.py @@ -0,0 +1,130 @@ +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', "") + 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() + diff --git a/cookbook.css b/cookbook.css new file mode 100644 index 0000000..caa3484 --- /dev/null +++ b/cookbook.css @@ -0,0 +1,58 @@ +#background-container { + background: $background; +} + +#header { + width: 100%; + background: $warning; + border: thick $warning-darken-1; + padding: 0 0; +} + +#header-components { + width: auto; + height: auto; + } + +#search-input { + width: 50; +} + +#recipe-list { + layout: grid; + grid-size: 3; + grid-gutter: 1; + grid-rows: 15; + margin: 1 0; + +} + +RecipeCard { + height: 100%; + width: 100%; + border: thick $accent; + background: $primary-background; + margin: 0 1; +} + +.invisible { + visibility: hidden; +} + + +.recipecard-label { + text-style: bold italic underline; + padding: 0 0 1 1; +} + +.rule-color { + color: $accent; +} + +.card { + padding: 0 2; +} + +.recipe-highlighted { + background: $primary-background-lighten-2; +} \ No newline at end of file