From 38ae34001af89f1f6d0e83211e9d95b590f03d1b Mon Sep 17 00:00:00 2001 From: Silberengel Date: Sun, 19 Apr 2026 15:52:06 +0200 Subject: [PATCH] bug-fixes --- src/imwald/core/author_html.py | 67 ++++++++++++++++++++++------------ src/imwald/ui/feed_page.py | 38 ++++++++++--------- src/imwald/ui/main_window.py | 3 ++ src/imwald/ui/theme.py | 38 ++++++++++--------- 4 files changed, 87 insertions(+), 59 deletions(-) diff --git a/src/imwald/core/author_html.py b/src/imwald/core/author_html.py index d525c8c..d9ee8cc 100644 --- a/src/imwald/core/author_html.py +++ b/src/imwald/core/author_html.py @@ -69,6 +69,7 @@ def format_nip05_chips_html( bad: str, chip_bg: str | None = None, chip_border: str | None = None, + container_margin_top: str | None = None, ) -> str: """ Horizontal row of NIP-05 chips: favicon (per domain), identifier, verification mark. @@ -89,30 +90,39 @@ def format_nip05_chips_html( f'style="vertical-align:middle;border-radius:3px;opacity:0.92" />' ) if okv is True: - mark = f'' + mark = f'' elif okv is False: - mark = f'' + mark = f'' else: - mark = f'' + mark = f'' if chip_bg: brd = chip_border or dim wrap = ( - "display:inline-flex;align-items:center;gap:8px;padding:8px 16px;" - "margin:0 18px 12px 0;" + "display:inline-flex;align-items:center;gap:10px;padding:10px 18px;" + "margin:0 12px 10px 0;" f"border-radius:999px;background:{chip_bg};border:1px solid {brd}" ) else: - wrap = "display:inline-flex;align-items:center;gap:6px;padding:2px 6px;margin:0 12px 8px 0" + wrap = ( + "display:inline-flex;align-items:center;gap:10px;padding:4px 4px 4px 0;" + "margin:0 16px 6px 0" + ) parts.append( f'' f"{icon}" - f'{esc}{mark}' + f'{esc}{mark}' f"" ) if not parts: return "" - mt = "14px" if chip_bg else "6px" - return f'
{"".join(parts)}
' + if container_margin_top is not None: + mt = container_margin_top + else: + mt = "14px" if chip_bg else "4px" + return ( + f'
{"".join(parts)}
' + ) def feed_op_author_compact_html( @@ -122,37 +132,48 @@ def feed_op_author_compact_html( *, status_inner_html: str, nip05_chips_html: str, - muted: str, + event_meta_inner_html: str, + header_bg: str, border: str, text: str, dim: str, ) -> str: - """Feed OP header: larger avatar, display name, compact npub line, NIP-38 + NIP-05.""" + """Feed OP header: name + optional NIP-38, then avatar beside npub / NIP-05 / event meta in a card.""" pk_l = pubkey_hex.strip().lower() href = html.escape(f"imwald://pub/{pk_l}", quote=True) av = avatar_img_or_placeholder(parsed, 64, border_hex=border, profile_href=href) name_e = html.escape(display_name_from_profile_or_hex(parsed, pubkey_hex)) npub_line, npub_title = _npub_header_lines(npub_bech) - status_block = "" + nip38_block = "" if status_inner_html.strip(): - status_block = ( - f'
' + nip38_block = ( + f'
' f"{status_inner_html}
" ) + meta_block = "" + if event_meta_inner_html.strip(): + meta_block = ( + f'
{event_meta_inner_html}
' + ) + row_mt = "12px" if nip38_block else "8px" return ( - f'
' - f"{av}" - f'
' + f'
' f'' - f'
' + f'
' f"{name_e}
" - f'
{npub_line}
' f"
" - f"{status_block}" + f"{nip38_block}" + f'
' + f"{av}" + f'
' + f'' + f'
{npub_line}
' + f"
" f"{nip05_chips_html}" - f"
" + f"{meta_block}" + f"
" ) diff --git a/src/imwald/ui/feed_page.py b/src/imwald/ui/feed_page.py index e7e2974..5689173 100644 --- a/src/imwald/ui/feed_page.py +++ b/src/imwald/ui/feed_page.py @@ -47,7 +47,7 @@ from imwald.core.nostr_engine import NostrEngine from imwald.core.ranker import Ranker from imwald.ui.media_viewer_dialog import try_open_media_url_in_app from imwald.ui.note_text_browser import NoteTextBrowser -from imwald.ui.theme import ACCENT, BG_CODE, BORDER, FEED_DOC_CSS, TEXT, TEXT_DIM, TEXT_MUTED +from imwald.ui.theme import ACCENT, BG_CARD, BORDER, FEED_DOC_CSS, TEXT, TEXT_DIM, TEXT_MUTED FEED_KINDS = (1, 20, 21, 30023, 9802, 11) @@ -497,8 +497,9 @@ class FeedPage(QWidget): dim=TEXT_DIM, ok=ACCENT, bad="#b86a6a", - chip_bg=BG_CODE, - chip_border=BORDER, + chip_bg=None, + chip_border=None, + container_margin_top="0", ) st_ev = get_active_user_status_event(self._db, pk) st_html = "" @@ -509,13 +510,27 @@ class FeedPage(QWidget): nip30_tags=_nip30_tags(st_ev), nip30_author_pubkey=pk, ) + try: + cts = int(ev["created_at"]) + rel_time, abs_time = relative_event_time_labels(cts) + except (TypeError, ValueError, OSError): + rel_time = str(ev.get("created_at") or "") + abs_time = rel_time + rel_e = html.escape(rel_time, quote=False) + abs_title = html.escape(abs_time, quote=True) + meta_inner = ( + f"Kind {int(ev['kind'])}" + f" · " + f"{rel_e}" + ) author_block = feed_op_author_compact_html( parsed, npub, pk, status_inner_html=st_html, nip05_chips_html=chips, - muted=TEXT_MUTED, + event_meta_inner_html=meta_inner, + header_bg=BG_CARD, border=BORDER, text=TEXT, dim=TEXT_DIM, @@ -527,14 +542,6 @@ class FeedPage(QWidget): f"
" f"Trending slice (nostrarchives)
" ) - try: - cts = int(ev["created_at"]) - rel_time, abs_time = relative_event_time_labels(cts) - except (TypeError, ValueError, OSError): - rel_time = str(ev.get("created_at") or "") - abs_time = rel_time - rel_e = html.escape(rel_time, quote=False) - abs_title = html.escape(abs_time, quote=True) eid_raw = str(ev["id"]) if len(eid_raw) > 52: eid_display = html.escape(eid_raw[:22] + "…" + eid_raw[-18:]) @@ -551,13 +558,8 @@ class FeedPage(QWidget): "" f"{FEED_DOC_CSS}" f"{author_block}" - f"
" - f"Kind {int(ev['kind'])}" - f" · " - f"{rel_e}" - f"
" f"{tr}" - f'
{md_body}
' + f'
{md_body}
' f'

{eid_display}

' "" diff --git a/src/imwald/ui/main_window.py b/src/imwald/ui/main_window.py index a81bfe6..b2833f3 100644 --- a/src/imwald/ui/main_window.py +++ b/src/imwald/ui/main_window.py @@ -24,6 +24,7 @@ from PySide6.QtWidgets import ( QSpinBox, QSplitter, QStackedWidget, + QTabBar, QTabWidget, QToolBar, QVBoxLayout, @@ -124,6 +125,8 @@ class MainWindow(QMainWindow): self._browser_tabs.setMovable(True) self._browser_tabs.tabCloseRequested.connect(self._on_browser_tab_close) self._browser_tabs.addTab(self._feed, "Feed") + # Feed is not closable (_on_browser_tab_close ignores index 0); hide the redundant control. + self._browser_tabs.tabBar().setTabButton(0, QTabBar.ButtonPosition.RightSide, None) self._profile_tabs_by_pubkey: dict[str, ProfilePage] = {} self._search = SearchPage(db) self._notif = NotificationsPage(db, self._accounts) diff --git a/src/imwald/ui/theme.py b/src/imwald/ui/theme.py index a835532..be2f2ac 100644 --- a/src/imwald/ui/theme.py +++ b/src/imwald/ui/theme.py @@ -2,7 +2,7 @@ from __future__ import annotations -import base64 +from urllib.parse import quote from PySide6.QtWidgets import QApplication @@ -21,13 +21,13 @@ BG_CARD = "#151f1a" BORDER = "#2a3d34" BG_CODE = "#0a100d" -# Fusion’s default tab-close pixmap is nearly invisible on our dark tabs; use an explicit “×”. -_TAB_CLOSE_ICON_B64 = base64.standard_b64encode( - b'' - b'' - b"" -).decode("ascii") -_TAB_CLOSE_ICON_URL = f'url("data:image/svg+xml;base64,{_TAB_CLOSE_ICON_B64}")' +# Fusion often fails to paint base64 SVG ``image:`` URLs on tab close buttons; UTF-8 data URL is more reliable. +_TAB_CLOSE_SVG = ( + '' + '' + "" +) +_TAB_CLOSE_ICON_URL = "url(\"data:image/svg+xml;charset=utf-8," + quote(_TAB_CLOSE_SVG, safe="") + "\")" _W = IMAGE_DISPLAY_MAX_WIDTH_PX FEED_DOC_CSS = f""" @@ -147,7 +147,7 @@ QTabBar::tab {{ color: {TEXT_DIM}; font-size: 15px; min-height: 22px; - padding: 10px 36px 11px 18px; + padding: 10px 52px 11px 18px; margin: 8px 5px 0 0; border: 1px solid {BORDER}; border-bottom: none; @@ -158,7 +158,7 @@ QTabBar::tab:selected {{ background-color: {BG_FIELD}; color: {TEXT}; font-weight: 600; - padding: 10px 36px 12px 18px; + padding: 10px 52px 12px 18px; margin-bottom: -1px; border-color: {BORDER}; border-bottom-color: {BG_FIELD}; @@ -171,21 +171,23 @@ QTabBar::close-button {{ subcontrol-origin: padding; subcontrol-position: right; image: {_TAB_CLOSE_ICON_URL}; - width: 26px; - height: 26px; - margin: 0 4px 0 6px; + width: 30px; + height: 30px; + min-width: 30px; + min-height: 30px; + margin: 0 6px 0 4px; padding: 5px; border-radius: 8px; - background-color: {BG_CODE}; - border: 1px solid {BORDER}; + background-color: {TEXT_DIM}; + border: 2px solid {BORDER}; }} QTabBar::close-button:hover {{ - background-color: {BG_CARD}; - border: 1px solid {ACCENT}; + background-color: {TEXT_MUTED}; + border: 2px solid {ACCENT}; }} QTabBar::close-button:pressed {{ background-color: {BG_FIELD}; - border: 1px solid {ACCENT_SOFT}; + border: 2px solid {ACCENT_SOFT}; }} QComboBox {{ background-color: {BG_FIELD};