Replace content CLI with Textual TUI
This commit is contained in:
1 parent
0d58ddd430
commit
737700a9a8
28 files changed
+2403
-167
No files matched your search
@@ -0,0 +1,73 @@
|
||||
from rich.markup import escape
|
||||
from textual import on
|
||||
from textual.app import ComposeResult
|
||||
from textual.binding import Binding
|
||||
from textual.containers import Horizontal, VerticalScroll
|
||||
from textual.widgets import DataTable, Static
|
||||
|
||||
import portfolio
|
||||
from fields import get_path, to_form_text
|
||||
from tui.content_pane import ContentPane
|
||||
from tui.record_editor import RecordEditor
|
||||
|
||||
PREVIEW_LENGTH = 60
|
||||
|
||||
|
||||
class ProfilePane(ContentPane):
|
||||
BINDINGS = [
|
||||
Binding("e", "edit", "Edit"),
|
||||
Binding("r", "reload", "Reload"),
|
||||
]
|
||||
|
||||
content_file = portfolio.PROFILE.file
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with Horizontal(classes="split-layout"):
|
||||
yield DataTable(cursor_type="row", zebra_stripes=True)
|
||||
with VerticalScroll(classes="detail-scroll"):
|
||||
yield Static("", id="profile-detail")
|
||||
|
||||
def on_mount(self):
|
||||
table = self.table()
|
||||
table.add_column("Field", key="field")
|
||||
table.add_column("Value", key="value")
|
||||
self.reload()
|
||||
|
||||
def reload(self, focus_key: str | None = None):
|
||||
profile = portfolio.load_records(portfolio.PROFILE)
|
||||
table = self.table()
|
||||
table.clear()
|
||||
for spec in portfolio.PROFILE.fields:
|
||||
text = to_form_text(spec.kind, get_path(profile, spec.path)).replace("\n", " · ")
|
||||
preview = text if len(text) <= PREVIEW_LENGTH else text[:PREVIEW_LENGTH] + "..."
|
||||
table.add_row(spec.label, preview, key=spec.path)
|
||||
self.restore_cursor(focus_key)
|
||||
self.show_field(self.selected_key())
|
||||
|
||||
def show_field(self, path: str | None):
|
||||
spec = next((item for item in portfolio.PROFILE.fields if item.path == path), None)
|
||||
detail = self.query_one("#profile-detail", Static)
|
||||
if not spec:
|
||||
detail.update("")
|
||||
return
|
||||
value = to_form_text(spec.kind, get_path(portfolio.load_records(portfolio.PROFILE), spec.path))
|
||||
hint = f"\n[dim]{spec.hint}[/dim]" if spec.hint else ""
|
||||
detail.update(f"[b]{escape(spec.label)}[/b]{hint}\n\n{escape(value) or '[dim]empty[/dim]'}\n\n[dim]Press e or Enter to edit the profile.[/dim]")
|
||||
|
||||
@on(DataTable.RowHighlighted)
|
||||
def highlight_changed(self, event: DataTable.RowHighlighted):
|
||||
self.show_field(event.row_key.value if event.row_key else None)
|
||||
|
||||
@on(DataTable.RowSelected)
|
||||
def row_selected(self):
|
||||
self.action_edit()
|
||||
|
||||
def action_edit(self):
|
||||
profile = portfolio.load_records(portfolio.PROFILE)
|
||||
focus_key = self.selected_key()
|
||||
|
||||
def saved(result: dict | None):
|
||||
if result is not None:
|
||||
self.run_now(lambda: portfolio.save_record(portfolio.PROFILE, None, result), "Saved profile", focus_key)
|
||||
|
||||
self.app.push_screen(RecordEditor("Edit profile", portfolio.PROFILE.fields, profile), saved)
|
||||
Reference in new issue
Block a user