From 1c1fb069f7f3bae5946c485ef48846c150ef1d54 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Wed, 21 Oct 2026 10:09:46 +0200 Subject: Detail panes: navigation as a button on top, reflowed descriptions Open in Hints and Open in Packages were plain links at the end of the pane, below the fold on a long one. ui.nav_button() makes them buttons, first in the pane; the UI guideline now says navigation buttons. The Repository description drops slack-desc's 70-column breaks. Co-Authored-By: Claude Opus 5.5 --- sb_builder/packages.py | 9 +++------ sb_builder/repository.py | 18 +++++++++--------- sb_builder/ui.py | 7 +++++++ 3 files changed, 19 insertions(+), 15 deletions(-) (limited to 'sb_builder') diff --git a/sb_builder/packages.py b/sb_builder/packages.py index a3d7126..dbbbd30 100644 --- a/sb_builder/packages.py +++ b/sb_builder/packages.py @@ -27,7 +27,7 @@ from PyQt6.QtWidgets import (QHBoxLayout, QLabel, QMessageBox, QScrollArea, QSpl from . import hints as hintlib from .dashboard import STATUS from .fmt import NA, fmt_time -from .ui import SP, action, chip, enable, group_label, search_field +from .ui import SP, action, chip, enable, group_label, nav_button, search_field OVERLAYS = ("personal", "pentesting") STATUSES = ("ok", "failed", "never", "outdated", "newer") @@ -303,14 +303,11 @@ class PackagesTab(QWidget): alignment=Qt.AlignmentFlag.AlignTop) self.detail.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) self.detail.setContentsMargins(12, 8, 12, 8) - # navigation, not an action: a link in the pane (UI guidelines) - self.open_hint_btn = QLabel('Open in Hints') - self.open_hint_btn.setContentsMargins(12, 0, 12, 8) - self.open_hint_btn.linkActivated.connect(lambda _l: self.hints_requested.emit(self.current()["name"])) + self.open_hint_btn = nav_button("Open in Hints", lambda: self.hints_requested.emit(self.current()["name"])) pane = QWidget() pane_layout = QVBoxLayout(pane) + pane_layout.addWidget(self.open_hint_btn, alignment=Qt.AlignmentFlag.AlignLeft) pane_layout.addWidget(self.detail) - pane_layout.addWidget(self.open_hint_btn) pane_layout.addStretch() scroll = QScrollArea(widgetResizable=True) scroll.setWidget(pane) diff --git a/sb_builder/repository.py b/sb_builder/repository.py index 1eae22e..29fd5f4 100644 --- a/sb_builder/repository.py +++ b/sb_builder/repository.py @@ -30,7 +30,7 @@ from PyQt6.QtWidgets import QHBoxLayout, QLabel, QScrollArea, QSplitter, QTableV from .dashboard import CARD_STYLE, Tile from .fmt import NA, fmt_age, fmt_bytes, fmt_time from .packages import OVERLAYS, table -from .ui import SP, action, chip, group_label, search_field +from .ui import SP, action, chip, group_label, nav_button, search_field PKGFILE = re.compile(r"^(?P.+)-(?P[^-]+)-(?P[^-]+)-(?P[^-]+)\.t[gx]z$") # category/pkg/file: text; a long one is indented, its text on the next line @@ -195,7 +195,8 @@ class Filter(QSortFilterProxyModel): def detail_html(r): e = html.escape out = [f"

{e(r['name'])} {e(r['version'])}

", - f"

{e(r['desc'])}

" if r["desc"] else "", + # slack-desc wraps at 70 columns: reflow, blank lines keep paragraphs + "".join(f"

{e(' '.join(p.split()))}

" for p in r["desc"].split("\n\n")), table([("file", r["file"]), ("size", fmt_bytes(r["size"])), ("uncompressed", fmt_bytes(r["usize"])), ("built", fmt_time(r["mtime"])), ("published", "yes" if r["published"] else "no, not in PACKAGES.TXT")])] @@ -236,21 +237,20 @@ class RepositoryTab(QWidget): self.table.setSelectionMode(QTableView.SelectionMode.SingleSelection) self.table.verticalHeader().hide() self.table.horizontalHeader().setStretchLastSection(True) - for col, width in enumerate((220, 120, 80, 110, 90, 150)): + for col, width in enumerate((220, 120, 80, 110, 90, 170)): self.table.setColumnWidth(col, width) self.table.selectionModel().currentRowChanged.connect(self.show_detail) self.detail = QLabel(textFormat=Qt.TextFormat.RichText, wordWrap=True, alignment=Qt.AlignmentFlag.AlignTop) self.detail.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) self.detail.setContentsMargins(12, 8, 12, 8) - # navigation, not an action: a link in the pane (UI guidelines) - self.link = QLabel('Open in Packages', visible=False) - self.link.setContentsMargins(12, 0, 12, 8) - self.link.linkActivated.connect(lambda _l: self.packages_requested.emit(self.current()["name"])) + self.open_packages_btn = nav_button("Open in Packages", + lambda: self.packages_requested.emit(self.current()["name"])) + self.open_packages_btn.hide() pane = QWidget() pane_layout = QVBoxLayout(pane) + pane_layout.addWidget(self.open_packages_btn, alignment=Qt.AlignmentFlag.AlignLeft) pane_layout.addWidget(self.detail) - pane_layout.addWidget(self.link) pane_layout.addStretch() scroll = QScrollArea(widgetResizable=True) scroll.setWidget(pane) @@ -323,4 +323,4 @@ class RepositoryTab(QWidget): def show_detail(self, current, _previous): row = current.data(Qt.ItemDataRole.UserRole) if current.isValid() else None self.detail.setText(detail_html(row) if row else "") - self.link.setVisible(bool(row)) + self.open_packages_btn.setVisible(bool(row)) diff --git a/sb_builder/ui.py b/sb_builder/ui.py index 3f02515..2321566 100644 --- a/sb_builder/ui.py +++ b/sb_builder/ui.py @@ -81,6 +81,13 @@ def group_label(text): return label +def nav_button(text, slot): + """A detail pane's jump to another tab: navigation, so it lives in the view.""" + b = QPushButton(QIcon.fromTheme("go-next", QApplication.style().standardIcon(SP.SP_ArrowForward)), text) + b.clicked.connect(lambda _checked=False: slot()) + return b + + def search_field(placeholder): q = QLineEdit(placeholderText=placeholder, clearButtonEnabled=True) icon = QIcon.fromTheme("edit-find", QApplication.style().standardIcon(SP.SP_FileDialogContentsView)) -- cgit v1.2.3