From 6d7a3b31463391a1b9469cf460a4ac2f77c37762 Mon Sep 17 00:00:00 2001 From: SpookyDervish Date: Wed, 4 Feb 2026 21:34:48 +1100 Subject: [PATCH] building out ui, still not done --- banner.txt => assets/banner.txt | 0 assets/repo_view_screen.tcss | 78 +++++++++++++++++++++++++++++++++ main.py | 3 +- screens/repo_view_screen.py | 71 ++++++++++++++++++++++++++++-- screens/search_screen.py | 9 +++- screens/welcome_screen.py | 14 +++--- 6 files changed, 164 insertions(+), 11 deletions(-) rename banner.txt => assets/banner.txt (100%) create mode 100644 assets/repo_view_screen.tcss diff --git a/banner.txt b/assets/banner.txt similarity index 100% rename from banner.txt rename to assets/banner.txt diff --git a/assets/repo_view_screen.tcss b/assets/repo_view_screen.tcss new file mode 100644 index 0000000..ac3f662 --- /dev/null +++ b/assets/repo_view_screen.tcss @@ -0,0 +1,78 @@ +#top { + background: $boost; + padding: 1 2 0 2; + #title { + height: 100%; + content-align: left middle; + width: auto; + } + + #buttons { + layout: horizontal; + Button { + margin-left: 1; + max-width: 13; + } + } + + Tabs { + width: 100%; + } + margin-bottom: 1; +} + +#repo-info { + width: 45; + padding: 0 1; + #search-query { + width: 1fr; + } + #search-btn { + max-width: 5; + } +} + +#files { + height: 5; + background: red 50%; + margin-left: 1; + border: tall $surface; + background: $background; + & > .datatable--header { + background: $surface; + } + +} + +#description { + margin-left: 1; +} + +#branch-info { + padding: 0 1; + background: $surface-darken-1; + border: tall $surface; + margin-bottom: 1; + Static { + width: 1fr; + text-align: center; + } +} + +#branch-options { + margin-bottom: 1; + + #new-pull-request { + max-width: 4; + } + + Select { + width: 16; + margin-right: 1; + } + + Button { + max-width: 16; + margin-right: 1; + } +} \ No newline at end of file diff --git a/main.py b/main.py index 614d05e..a7549d3 100644 --- a/main.py +++ b/main.py @@ -1,13 +1,12 @@ from textual.app import App, ComposeResult from screens.welcome_screen import WelcomeScreen -from screens.search_screen import SearchScreen class TuiGithub(App): GITEA_HOST = "https://chookspace.com/" def on_compose(self): - self.push_screen(SearchScreen()) + self.push_screen(WelcomeScreen()) if __name__ == "__main__": diff --git a/screens/repo_view_screen.py b/screens/repo_view_screen.py index 7fb2578..89712f9 100644 --- a/screens/repo_view_screen.py +++ b/screens/repo_view_screen.py @@ -1,11 +1,76 @@ from textual.screen import Screen from textual.app import ComposeResult +from textual.widgets import Input, Select, Static, DataTable, ContentSwitcher, Tabs, Tab, Button +from textual.containers import VerticalGroup, Vertical, HorizontalGroup, Right + from widgets import Navbar +import requests + class RepoViewScreen(Screen): - def __init__(self, repo_id: int): - super().__init__(self) + CSS_PATH = "../assets/repo_view_screen.tcss" + + def __init__(self, owner_name: str, repo_name: str): + super().__init__() + self.owner_name = owner_name + self.repo_name = repo_name def compose(self) -> ComposeResult: - yield Navbar() \ No newline at end of file + + # get repo data via a request + response = requests.get( + url=self.app.GITEA_HOST + f"api/v1/repos/{self.owner_name}/{self.repo_name}" + ) + if not response.ok: + self.notify(response.text, title="Failed to get repo:", severity="error") + yield Navbar() + return + data = response.json() + + + yield Navbar() + + with VerticalGroup(id="top"): + with HorizontalGroup(): + yield Static(f" {self.owner_name}/[b]{self.repo_name}[/]", id="title") + with Right(id="buttons"): + yield Button("Star [d](0)", variant="warning", flat=True) + yield Button("Watch [d](0)", flat=True) + yield Tabs( + "\uf44f Code", + "\uebf8 Issues", + "\ue726 Pull Requests", + "\uf500 Actions", + "\ueb29 Packages", + "\uf502 Projects", + "\uf02b Releases", + "\ueaa4 Wiki", + "\uf21e Activity" + ) + + with ContentSwitcher(initial="Code"): + with HorizontalGroup(id="Code"): + with Vertical(id="commits"): + with HorizontalGroup(id="branch-info"): + yield Static("\uf4b6 1 Commits") + yield Static("\uf418 1 Branch") + yield Static("\uf02b 0 Tags") + + with HorizontalGroup(id="branch-options"): + yield Select.from_values([ + "main" + ], allow_blank=False, id="branch") + yield Button("\ue726", flat=True, id="new-pull-request", tooltip="New Pull Request") + yield Button("Go to file", flat=True) + + table = DataTable(id="files", show_cursor=False) + table.add_columns("SpookyDervish [r]9b32c417e9[/]", "switched from tabs to spaces", "51 minutes ago") + table.add_row("\ue5ff screens", "[d]switched from tabs to spaces", "[d]51 minutes ago") + yield table + with Vertical(id="repo-info"): + with HorizontalGroup(): + yield Input("Search code...", id="search-query") + yield Button("\uf002", flat=True, id="search-btn") + yield Static("\n[b] Description") + yield Static("[d]" + data["description"], id="description") \ No newline at end of file diff --git a/screens/search_screen.py b/screens/search_screen.py index 5e83cd9..3c08aa4 100644 --- a/screens/search_screen.py +++ b/screens/search_screen.py @@ -4,6 +4,8 @@ from textual.widgets import Input, Select, LoadingIndicator, Static from textual.containers import HorizontalGroup, ScrollableContainer from textual.app import ComposeResult +from screens.repo_view_screen import RepoViewScreen + from human_readable import time_delta from datetime import datetime, timedelta @@ -38,9 +40,11 @@ class SearchResult(HorizontalGroup): self.is_fork = repo_data["fork"] self.updated_at = datetime.fromisoformat(repo_data["updated_at"]).replace(tzinfo=None) + + def compose(self) -> ComposeResult: updated_string = time_delta(datetime.now() - self.updated_at) - yield Static(f"[@click='view_user({self.author["id"]})']{self.author["login"]}[/] / [@click=view_repo('')]{self.repo_name}[/]{' [d]\[[cyan]fork[/]]' if self.is_fork else ''}\n{self.description}\n[d]Updated {updated_string} ago") + yield Static(f"[@click='view_user({self.author["id"]})']{self.author["login"]}[/] / [@click='screen.view_repo(\"{self.author["login"]}\",\"{self.repo_name}\")']{self.repo_name}[/]{' [d]\[[cyan]fork[/]]' if self.is_fork else ''}\n{self.description}\n[d]Updated {updated_string} ago") class SearchScreen(Screen): DEFAULT_CSS = """ @@ -58,6 +62,9 @@ class SearchScreen(Screen): } } """ + + def action_view_repo(self, author: str, repo_name: str): + self.app.switch_screen(RepoViewScreen(author, repo_name)) def action_search_query(self): query_input = self.query_one("#query") diff --git a/screens/welcome_screen.py b/screens/welcome_screen.py index 7e5cc26..de8205f 100644 --- a/screens/welcome_screen.py +++ b/screens/welcome_screen.py @@ -4,6 +4,7 @@ from textual.app import ComposeResult from textual.widgets import Static, Button from textualeffects.widgets import EffectLabel, EffectType, effects +from screens.search_screen import SearchScreen from widgets import Navbar from random import choice @@ -14,7 +15,7 @@ class WelcomeScreen(Screen): Center { padding: 2; width: 100%; - + Static { text-align: center; } @@ -33,15 +34,18 @@ class WelcomeScreen(Screen): } } """ + + def on_button_pressed(self, event: Button.Pressed): + if event.button.id == "explore": + self.app.switch_screen(SearchScreen()) def compose(self) -> ComposeResult: yield Navbar() with Center(): - with open("banner.txt", "r") as f: + with open("assets/banner.txt", "r") as f: yield EffectLabel(text=f.read(), effect=choice(list(effects.keys()))) - yield Static("[d]Gitea, in your terminal.[/]") + yield Static("[white]Gitea, in your terminal.") with HorizontalGroup(id="buttons"): - yield Button("Explore", variant="primary", flat=True) - yield Button("another button lol", flat=True) \ No newline at end of file + yield Button("\uee45 Explore", variant="primary", flat=True, id="explore") \ No newline at end of file