diff --git a/cognee/cli/tui/add_screen.py b/cognee/cli/tui/add_screen.py index d647c5edf..66ca7a7b4 100644 --- a/cognee/cli/tui/add_screen.py +++ b/cognee/cli/tui/add_screen.py @@ -18,62 +18,10 @@ class AddTUIScreen(BaseTUIScreen): ] CSS = BaseTUIScreen.CSS + """ - AddTUIScreen { - background: $surface; - } - - #add-container { - height: auto; - padding: 1; - content-align: center middle; - } - - #add-form { - width: 100%; - height: auto; - border: solid $primary; - padding: 2; - background: $surface; - } - - #form-title { - text-align: center; - width: 100%; - text-style: bold; - color: $accent; - margin-bottom: 2; - } - - .field-label { - color: $text-muted; - margin-top: 1; - margin-bottom: 1; - } - - Input { - width: 100%; - margin-bottom: 1; - } - #data-input { height: 8; min-height: 8; } - - #status-message { - margin-top: 2; - text-align: center; - height: auto; - } - - #add-footer { - dock: bottom; - padding: 1 0; - background: $boost; - color: $text-muted; - content-align: center middle; - border: solid $primary; - } """ def __init__(self): @@ -81,27 +29,27 @@ class AddTUIScreen(BaseTUIScreen): self.is_processing = False def compose_content(self) -> ComposeResult: - with Container(id="add-container"): - yield Label("Add Data to Cognee", id="form-title") - with Vertical(id="add-form"): - yield Label("Data (text, file path, URL, or S3 path):", classes="field-label") + with Container(classes="tui-content-container"): + yield Label("Add Data to Cognee", classes="tui-title") + with Vertical(classes="tui-form"): + yield Label("Data (text, file path, URL, or S3 path):", classes="tui-label-spaced") yield TextArea( "", id="data-input", ) - yield Label("Dataset Name:", classes="field-label") + yield Label("Dataset Name:", classes="tui-label-spaced") yield Input( placeholder="main_dataset", value="main_dataset", id="dataset-input" ) - yield Static("", id="status-message") + yield Static("", classes="tui-status") def compose_footer(self) -> ComposeResult: yield Static( "Ctrl+S: Add • Esc: Back • q: Quit", - id="add-footer" + classes="tui-footer" ) def on_mount(self) -> None: @@ -136,7 +84,7 @@ class AddTUIScreen(BaseTUIScreen): """Process and submit the data.""" data_input = self.query_one("#data-input", TextArea) dataset_input = self.query_one("#dataset-input", Input) - status = self.query_one("#status-message", Static) + status = self.query_one(".tui-status", Static) data = data_input.text.strip() dataset_name = dataset_input.value.strip() or "main_dataset" @@ -158,7 +106,7 @@ class AddTUIScreen(BaseTUIScreen): async def _add_data_async(self, data: str, dataset_name: str) -> None: """Async function to add data to cognee.""" - status = self.query_one("#status-message", Static) + status = self.query_one(".tui-status", Static) try: import cognee diff --git a/cognee/cli/tui/base_screen.py b/cognee/cli/tui/base_screen.py index 6cd3f8dcc..7256e0353 100644 --- a/cognee/cli/tui/base_screen.py +++ b/cognee/cli/tui/base_screen.py @@ -3,13 +3,14 @@ from textual.app import ComposeResult from textual.widgets import Static from cognee.version import get_cognee_version +from cognee.cli.tui.common_styles import COMMON_STYLES class BaseTUIScreen(Screen): """Base screen class with constant header for all TUI screens.""" # Subclasses should override this CSS and add their own styles - CSS = """ + CSS = COMMON_STYLES + """ #header { dock: top; background: $boost; diff --git a/cognee/cli/tui/cognify_screen.py b/cognee/cli/tui/cognify_screen.py index 24eae1e6b..5d33377ea 100644 --- a/cognee/cli/tui/cognify_screen.py +++ b/cognee/cli/tui/cognify_screen.py @@ -18,43 +18,6 @@ class CognifyTUIScreen(BaseTUIScreen): ] CSS = BaseTUIScreen.CSS + """ - CognifyTUIScreen { - background: $surface; - } - - #cognify-container { - height: auto; - padding: 1; - content-align: center middle; - } - - #cognify-form { - width: 100%; - height: auto; - border: solid $primary; - padding: 2; - background: $surface; - } - - #form-title { - text-align: center; - width: 100%; - text-style: bold; - color: $accent; - margin-bottom: 2; - } - - .field-label { - color: $text-muted; - margin-top: 1; - margin-bottom: 1; - } - - Input { - width: 100%; - margin-bottom: 1; - } - Checkbox { margin-top: 1; margin-bottom: 1; @@ -69,21 +32,6 @@ class CognifyTUIScreen(BaseTUIScreen): RadioButton { height: 1; } - - #status-message { - margin-top: 2; - text-align: center; - height: auto; - } - - #cognify-footer { - dock: bottom; - padding: 1 0; - background: $boost; - color: $text-muted; - content-align: center middle; - border: solid $primary; - } """ def __init__(self): @@ -91,28 +39,28 @@ class CognifyTUIScreen(BaseTUIScreen): self.is_processing = False def compose_content(self) -> ComposeResult: - with Container(id="cognify-container"): - yield Label("⚡ Cognify Data", id="form-title") - with Vertical(id="cognify-form"): - yield Label("Dataset Name (optional, leave empty for all):", classes="field-label") + with Container(classes="tui-content-container"): + yield Label("⚡ Cognify Data", classes="tui-title") + with Vertical(classes="tui-form"): + yield Label("Dataset Name (optional, leave empty for all):", classes="tui-label-spaced") yield Input( placeholder="Leave empty to process all datasets", value="", id="dataset-input" ) - yield Label("Chunker Type:", classes="field-label") + yield Label("Chunker Type:", classes="tui-label-spaced") with RadioSet(id="chunker-radio"): for chunker in CHUNKER_CHOICES: yield RadioButton(chunker, value=(chunker == "TextChunker")) yield Checkbox("Run in background", id="background-checkbox") - yield Static("", id="status-message") + yield Static("", classes="tui-status") def compose_footer(self) -> ComposeResult: yield Static( "Ctrl+S: Start • Esc: Back • q: Quit", - id="cognify-footer" + classes="tui-footer" ) def on_mount(self) -> None: @@ -144,7 +92,7 @@ class CognifyTUIScreen(BaseTUIScreen): dataset_input = self.query_one("#dataset-input", Input) chunker_radio = self.query_one("#chunker-radio", RadioSet) background_checkbox = self.query_one("#background-checkbox", Checkbox) - status = self.query_one("#status-message", Static) + status = self.query_one(".tui-status", Static) dataset_name = dataset_input.value.strip() or None chunker_type = str(chunker_radio.pressed_button.label) if chunker_radio.pressed_button else "TextChunker" @@ -164,7 +112,7 @@ class CognifyTUIScreen(BaseTUIScreen): async def _cognify_async(self, dataset_name: str | None, chunker_type: str, run_background: bool) -> None: """Async function to cognify data.""" - status = self.query_one("#status-message", Static) + status = self.query_one(".tui-status", Static) try: import cognee diff --git a/cognee/cli/tui/common_styles.py b/cognee/cli/tui/common_styles.py new file mode 100644 index 000000000..a71949e1a --- /dev/null +++ b/cognee/cli/tui/common_styles.py @@ -0,0 +1,113 @@ +"""Common CSS styles for TUI screens to reduce repetition.""" + +COMMON_STYLES = """ +/* Common screen background */ +Screen { + background: $surface; +} + +/* Common container styles */ +.tui-container { + height: 100%; + padding: 1; +} + +.tui-content-container { + height: auto; + padding: 1; + content-align: center middle; +} + +.tui-form { + width: 100%; + height: auto; + border: solid $primary; + padding: 2; + background: $surface; +} + +.tui-form-compact { + border: solid $primary; + padding: 1; + background: $surface; +} + +/* Common title styles */ +.tui-title { + text-align: center; + text-style: bold; + color: $accent; + margin-bottom: 2; + width: 100%; +} + +/* Common label styles */ +.tui-label { + color: $text-muted; + margin-bottom: 1; +} + +.tui-label-spaced { + color: $text-muted; + margin-top: 1; + margin-bottom: 1; +} + +/* Common input styles */ +Input { + width: 100%; + margin-bottom: 1; +} + +/* Common button styles */ +Button { + margin: 0 1; +} + +/* Common status message styles */ +.tui-status { + text-align: center; + margin-top: 2; + height: auto; +} + +/* Common footer styles */ +.tui-footer { + dock: bottom; + padding: 1 0; + background: $boost; + color: $text-muted; + content-align: center middle; + border: solid $primary; +} + +/* Common dialog/modal styles */ +.tui-dialog { + border: thick $warning; + background: $surface; + padding: 2; +} + +.tui-dialog-title { + text-align: center; + text-style: bold; + color: $warning; + margin-bottom: 1; +} + +.tui-dialog-message { + text-align: center; + margin-bottom: 1; +} + +.tui-dialog-buttons { + align: center middle; + height: 3; +} + +/* Common input group styles */ +.tui-input-group { + height: auto; + margin-bottom: 2; +} +""" \ No newline at end of file diff --git a/cognee/cli/tui/config_screen.py b/cognee/cli/tui/config_screen.py index 27ff0b3e6..9b0780fe5 100644 --- a/cognee/cli/tui/config_screen.py +++ b/cognee/cli/tui/config_screen.py @@ -34,26 +34,10 @@ class ConfirmModal(Screen): padding: 1 2; } - #confirm-title { - text-align: center; - text-style: bold; - color: $warning; - margin-bottom: 1; - } - #confirm-message { text-align: center; margin-bottom: 2; } - - #confirm-buttons { - align: center middle; - height: 3; - } - - Button { - margin: 0 1; - } """ def __init__(self, key: str, default_value: str): @@ -63,10 +47,10 @@ class ConfirmModal(Screen): def compose(self) -> ComposeResult: with Container(id="confirm-dialog"): - yield Label("⚠ Reset Configuration", id="confirm-title") + yield Label("⚠ Reset Configuration", classes="tui-dialog-title") yield Label(f"Reset '{self.key}' to default?", id="confirm-message") yield Label(f"Default value: {self.default_value}", id="confirm-message") - with Horizontal(id="confirm-buttons"): + with Horizontal(classes="tui-dialog-buttons"): yield Button("Reset", variant="error", id="confirm-btn") yield Button("Cancel", variant="default", id="cancel-btn") @@ -94,10 +78,6 @@ class ConfigTUIScreen(BaseTUIScreen): ] CSS = BaseTUIScreen.CSS + """ - ConfigTUIScreen { - background: $surface; - } - #config-container { height: 100%; border: solid $primary; @@ -127,15 +107,6 @@ class ConfigTUIScreen(BaseTUIScreen): #inline-input { width: 100%; } - - #config-footer { - dock: bottom; - padding: 1 0; - background: $boost; - color: $text-muted; - content-align: center middle; - border: solid $primary; - } """ # Config key mappings with defaults (from existing config.py) @@ -158,6 +129,7 @@ class ConfigTUIScreen(BaseTUIScreen): def compose_content(self) -> ComposeResult: with Container(id="config-container"): + yield Static("⚙️ Change Config", classes="tui-title") table = DataTable() table.cursor_type = "row" table.zebra_stripes = True @@ -169,7 +141,7 @@ class ConfigTUIScreen(BaseTUIScreen): def compose_footer(self) -> ComposeResult: yield Static( "↑↓: Navigate • e: Edit • Enter: Save • r: Reset • Esc: Back • q: Quit", - id="config-footer" + classes="tui-footer" ) def on_mount(self) -> None: diff --git a/cognee/cli/tui/delete_screen.py b/cognee/cli/tui/delete_screen.py index bfd204147..69701cf69 100644 --- a/cognee/cli/tui/delete_screen.py +++ b/cognee/cli/tui/delete_screen.py @@ -19,10 +19,6 @@ class DeleteTUIScreen(BaseTUIScreen): ] CSS = BaseTUIScreen.CSS + """ - DeleteTUIScreen { - background: $surface; - } - #delete-container { height: auto; padding: 2; @@ -31,33 +27,6 @@ class DeleteTUIScreen(BaseTUIScreen): #delete-form { width: 80; - height: auto; - border: solid $primary; - background: $surface; - padding: 2; - } - - #form-title { - text-align: center; - text-style: bold; - color: $accent; - margin-bottom: 2; - width: 100%; - } - - .input-group { - height: auto; - margin-bottom: 2; - } - - .input-label { - color: $text-muted; - margin-bottom: 1; - } - - Input { - width: 100%; - margin-bottom: 1; } #button-group { @@ -65,25 +34,6 @@ class DeleteTUIScreen(BaseTUIScreen): align: center middle; margin-top: 2; } - - Button { - margin: 0 1; - } - - #status-message { - text-align: center; - margin-top: 2; - height: auto; - } - - #delete-footer { - dock: bottom; - padding: 1 0; - background: $boost; - color: $text-muted; - content-align: center middle; - border: solid $primary; - } """ def __init__(self): @@ -92,18 +42,18 @@ class DeleteTUIScreen(BaseTUIScreen): def compose_content(self) -> ComposeResult: with Container(id="delete-container"): - with Vertical(id="delete-form"): - yield Label("🗑️ Delete Data", id="form-title") + with Vertical(id="delete-form", classes="tui-form"): + yield Label("🗑️ Delete Data", classes="tui-title") - with Vertical(classes="input-group"): - yield Label("Dataset Name (optional):", classes="input-label") + with Vertical(classes="tui-input-group"): + yield Label("Dataset Name (optional):", classes="tui-label") yield Input( placeholder="Enter dataset name to delete specific dataset", id="dataset-input" ) - with Vertical(classes="input-group"): - yield Label("User ID (optional):", classes="input-label") + with Vertical(classes="tui-input-group"): + yield Label("User ID (optional):", classes="tui-label") yield Input( placeholder="Enter user ID to delete user's data", id="user-input" @@ -113,12 +63,12 @@ class DeleteTUIScreen(BaseTUIScreen): yield Button("Delete", variant="error", id="delete-btn") yield Button("Delete All", variant="error", id="delete-all-btn") - yield Static("", id="status-message") + yield Static("", classes="tui-status") def compose_footer(self) -> ComposeResult: yield Static( "Ctrl+s: Delete • Ctrl+d: Delete All • Esc: Back • q: Quit", - id="delete-footer" + classes="tui-footer" ) def on_mount(self) -> None: @@ -161,7 +111,7 @@ class DeleteTUIScreen(BaseTUIScreen): dataset_input = self.query_one("#dataset-input", Input) user_input = self.query_one("#user-input", Input) - status = self.query_one("#status-message", Static) + status = self.query_one(".tui-status", Static) dataset_name = dataset_input.value.strip() or None user_id = user_input.value.strip() or None @@ -224,7 +174,7 @@ class DeleteTUIScreen(BaseTUIScreen): async def _perform_delete_all(self) -> None: """Perform the actual delete all operation.""" - status = self.query_one("#status-message", Static) + status = self.query_one(".tui-status", Static) self.is_processing = True try: @@ -295,34 +245,20 @@ class DeleteAllConfirmModal(BaseTUIScreen): margin-bottom: 1; } - #confirm-message { - text-align: center; - margin-bottom: 1; - } - #confirm-warning { text-align: center; color: $warning; text-style: bold; margin-bottom: 2; } - - #confirm-buttons { - align: center middle; - height: 3; - } - - Button { - margin: 0 1; - } """ def compose_content(self) -> ComposeResult: with Container(id="confirm-dialog"): yield Label("⚠️ DELETE ALL DATA", id="confirm-title") - yield Label("This will delete ALL data from cognee", id="confirm-message") + yield Label("This will delete ALL data from cognee", classes="tui-dialog-message") yield Label("This operation is IRREVERSIBLE!", id="confirm-warning") - with Horizontal(id="confirm-buttons"): + with Horizontal(classes="tui-dialog-buttons"): yield Button("Delete All", variant="error", id="confirm-btn") yield Button("Cancel", variant="default", id="cancel-btn") diff --git a/cognee/cli/tui/home_screen.py b/cognee/cli/tui/home_screen.py index 77a3bbc0c..b7ea94db0 100644 --- a/cognee/cli/tui/home_screen.py +++ b/cognee/cli/tui/home_screen.py @@ -35,10 +35,6 @@ class HomeScreen(BaseTUIScreen): ] CSS = BaseTUIScreen.CSS + """ - HomeScreen { - background: $surface; - } - #main-container { height: 100%; border: solid $primary; @@ -64,13 +60,6 @@ class HomeScreen(BaseTUIScreen): margin-bottom: 2; } - #title-sub { - text-align: center; - width: auto; - color: $text-muted; - padding-bottom: 1; - margin-bottom: 1; - } ListView > ListItem { width: 100%; @@ -144,15 +133,6 @@ class HomeScreen(BaseTUIScreen): padding-left: 1; color: $text-muted; } - - #home-footer { - dock: bottom; - padding: 1 0; - background: $boost; - color: $text-muted; - content-align: center middle; - border: solid $primary; - } """ def __init__(self): @@ -177,7 +157,7 @@ class HomeScreen(BaseTUIScreen): def compose_footer(self) -> ComposeResult: yield Static( "↑↓: Navigate • Enter: Select • q/Esc: Quit", - id="home-footer" + classes="tui-footer" ) def on_mount(self) -> None: diff --git a/cognee/cli/tui/search_screen.py b/cognee/cli/tui/search_screen.py index 4bfc14341..2ba42e673 100644 --- a/cognee/cli/tui/search_screen.py +++ b/cognee/cli/tui/search_screen.py @@ -17,10 +17,11 @@ class SearchTUIScreen(BaseTUIScreen): ] CSS = BaseTUIScreen.CSS + """ - SearchTUIScreen { - background: $surface; + #search-container { + height: 100%; + padding: 1; } - + #form-title { text-align: center; text-style: bold; @@ -29,12 +30,6 @@ class SearchTUIScreen(BaseTUIScreen): width: 100%; } - - #search-container { - height: 100%; - padding: 1; - } - #search-form { height: auto; border: solid $primary; @@ -67,21 +62,6 @@ class SearchTUIScreen(BaseTUIScreen): height: 1fr; overflow-y: auto; } - - .field-label { - color: $text-muted; - margin-top: 1; - margin-bottom: 1; - } - - #search-footer { - dock: bottom; - padding: 1 0; - background: $boost; - color: $text-muted; - content-align: center middle; - border: solid $primary; - } """ def __init__(self): @@ -92,9 +72,9 @@ class SearchTUIScreen(BaseTUIScreen): with Container(id="search-container"): yield Label("🔍 Search Data", id="form-title") with Vertical(id="search-form"): - yield Label("Query:", classes="field-label") + yield Label("Query:", classes="tui-label-spaced") yield Input(placeholder="Enter your search query...", id="query-input") - yield Label("Search Type:", classes="field-label") + yield Label("Search Type:", classes="tui-label-spaced") yield Select( [ ("Graph Completion (Recommended)", "GRAPH_COMPLETION"), @@ -114,7 +94,7 @@ class SearchTUIScreen(BaseTUIScreen): def compose_footer(self) -> ComposeResult: yield Static( "Ctrl+S: Search • Esc: Back • q: Quit", - id="search-footer" + classes="tui-footer" ) def on_mount(self) -> None: