""" Command Palette Widget for YouTube TUI """ from textual.app import ComposeResult from textual.containers import Container from textual.screen import ModalScreen from textual.widgets import Footer, Header, Input, ListView, ListItem, Static class CommandPalette(ModalScreen): """Command palette for quick access to actions""" DEFAULT_COMMANDS = [ ("Search", "Search for videos"), ("Download", "Quick download mode"), ("History", "Show search history"), ("Settings", "Open settings"), ("Help", "Show help screen"), ("Quit", "Quit application"), ] CSS = """ CommandPalette { align: center middle; } #palette-container { width: 60%; height: auto; border: solid #555555; background: $surface; padding: 1; } #palette-title { width: 100%; height: 3; dock: top; background: $primary; content-align: center middle; color: $text; } #palette-input { width: 100%; margin: 1 0; } #palette-list { width: 100%; height: 20; margin: 1 0; } #palette-actions { width: 100%; height: auto; dock: bottom; margin-top: 1; } ListItem { height: 3; padding: 0 1; } ListItem:hover { background: $primary-darken-2; } ListItem.--highlight { background: $primary; } .command-description { color: $text-muted; } """ BINDINGS = [ ("escape", "close_palette", "Close"), ("up", "cursor_up", "Cursor Up"), ("down", "cursor_down", "Cursor Down"), ("enter", "select_command", "Select"), ] def __init__(self): super().__init__() self.selected_index = 0 self.commands = self.DEFAULT_COMMANDS.copy() def compose(self) -> ComposeResult: """Compose the command palette""" yield Header() yield Container( Static("Command Palette", id="palette-title"), Input(placeholder="Type to filter commands...", id="palette-input"), ListView(id="palette-list-view"), id="palette-container", ) yield Footer() def on_mount(self) -> None: """Called when palette is mounted""" self.update_list() self.query_one(Input).focus() def update_list(self) -> None: """Update the command list""" input_widget = self.query_one("#palette-input", Input) filter_text = input_widget.value.lower() # Filter commands if filter_text: self.commands = [ (cmd, desc) for cmd, desc in self.DEFAULT_COMMANDS if filter_text in cmd.lower() or filter_text in desc.lower() ] else: self.commands = self.DEFAULT_COMMANDS.copy() # Update the list view list_view = self.query_one("#palette-list-view", ListView) list_view.clear() for i, (command, description) in enumerate(self.commands): item = ListItem( Static(f"[bold]{command}[/bold]\n{description}"), ) list_view.append(item) # Update selected index if needed if self.selected_index >= len(self.commands): self.selected_index = max(0, len(self.commands) - 1) # Highlight selected item self.highlight_selected() def highlight_selected(self) -> None: """Highlight the selected item""" list_view = self.query_one("#palette-list-view", ListView) for i, item in enumerate(list_view.children): if i == self.selected_index: item.add_class("--highlight") else: item.remove_class("--highlight") def action_cursor_up(self) -> None: """Move selection up""" if self.commands: self.selected_index = max(0, self.selected_index - 1) self.highlight_selected() def action_cursor_down(self) -> None: """Move selection down""" if self.commands: self.selected_index = min(len(self.commands) - 1, self.selected_index + 1) self.highlight_selected() def action_select_command(self) -> None: """Execute the selected command""" if not self.commands: return command = self.commands[self.selected_index][0] self.execute_command(command) def execute_command(self, command: str) -> None: """Execute a command""" if command == "Search": self.app.push_screen("search") self.app.pop_screen() elif command == "Download": # Go to search for quick download self.app.push_screen("search") self.app.pop_screen() elif command == "History": self.app.push_screen("history") elif command == "Settings": self.app.push_screen("settings") elif command == "Help": self.app.push_screen("help") elif command == "Quit": self.app.exit() def action_close_palette(self) -> None: """Close the palette""" self.app.pop_screen() def on_input_changed(self, event: Input.Changed) -> None: """Handle input changes""" self.update_list() def on_data_table_row_selected(self, event) -> None: """Handle row selection""" self.action_select_command()