|
|
|
@ -21,7 +21,12 @@ def avatar_img_or_placeholder( |
|
|
|
size_px: int, |
|
|
|
size_px: int, |
|
|
|
*, |
|
|
|
*, |
|
|
|
border_hex: str = "#2a3d34", |
|
|
|
border_hex: str = "#2a3d34", |
|
|
|
|
|
|
|
profile_href: str | None = None, |
|
|
|
) -> str: |
|
|
|
) -> str: |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
``profile_href``: if set (e.g. ``imwald://pub/…``), the avatar is clickable for that profile. |
|
|
|
|
|
|
|
If unset but a picture URL exists, the avatar links to the full-size image (same URL as ``src``). |
|
|
|
|
|
|
|
""" |
|
|
|
pic = safe_http_url(parsed.get("picture")) |
|
|
|
pic = safe_http_url(parsed.get("picture")) |
|
|
|
r = max(6, size_px // 5) |
|
|
|
r = max(6, size_px // 5) |
|
|
|
if pic: |
|
|
|
if pic: |
|
|
|
@ -29,6 +34,11 @@ def avatar_img_or_placeholder( |
|
|
|
f'<img src="{pic}" width="{size_px}" height="{size_px}" alt="" ' |
|
|
|
f'<img src="{pic}" width="{size_px}" height="{size_px}" alt="" ' |
|
|
|
f'style="border-radius:{r}px;object-fit:cover;vertical-align:middle;flex-shrink:0">' |
|
|
|
f'style="border-radius:{r}px;object-fit:cover;vertical-align:middle;flex-shrink:0">' |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
if profile_href: |
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
|
|
f'<a href="{profile_href}" title="View profile" ' |
|
|
|
|
|
|
|
f'style="text-decoration:none;display:inline-block">{img}</a>' |
|
|
|
|
|
|
|
) |
|
|
|
return ( |
|
|
|
return ( |
|
|
|
f'<a class="imwald-fullimg" href="{pic}" title="View full size" ' |
|
|
|
f'<a class="imwald-fullimg" href="{pic}" title="View full size" ' |
|
|
|
f'style="text-decoration:none;display:inline-block">{img}</a>' |
|
|
|
f'style="text-decoration:none;display:inline-block">{img}</a>' |
|
|
|
@ -55,11 +65,11 @@ def feed_op_author_block_html( |
|
|
|
) -> str: |
|
|
|
) -> str: |
|
|
|
"""Top-of-note author row: picture, display name, npub, optional nip05/about lines (links to profile tab).""" |
|
|
|
"""Top-of-note author row: picture, display name, npub, optional nip05/about lines (links to profile tab).""" |
|
|
|
disp = html.escape(display_name_from_profile(parsed)) |
|
|
|
disp = html.escape(display_name_from_profile(parsed)) |
|
|
|
av = avatar_img_or_placeholder(parsed, 52, border_hex=border) |
|
|
|
|
|
|
|
npub_e = html.escape(npub_bech) |
|
|
|
|
|
|
|
pk_s = html.escape(pk_short) |
|
|
|
|
|
|
|
pk_l = pubkey_hex.strip().lower() |
|
|
|
pk_l = pubkey_hex.strip().lower() |
|
|
|
href = html.escape(f"imwald://pub/{pk_l}", quote=True) |
|
|
|
href = html.escape(f"imwald://pub/{pk_l}", quote=True) |
|
|
|
|
|
|
|
av = avatar_img_or_placeholder(parsed, 52, border_hex=border, profile_href=href) |
|
|
|
|
|
|
|
npub_e = html.escape(npub_bech) |
|
|
|
|
|
|
|
pk_s = html.escape(pk_short) |
|
|
|
inner = ( |
|
|
|
inner = ( |
|
|
|
f'<div style="display:flex;align-items:flex-start;margin-bottom:12px">' |
|
|
|
f'<div style="display:flex;align-items:flex-start;margin-bottom:12px">' |
|
|
|
f"{av}" |
|
|
|
f"{av}" |
|
|
|
@ -86,11 +96,11 @@ def thread_reply_author_row_html( |
|
|
|
border: str, |
|
|
|
border: str, |
|
|
|
) -> str: |
|
|
|
) -> str: |
|
|
|
"""Single-row author badge for thread replies (avatar + kind + name + npub).""" |
|
|
|
"""Single-row author badge for thread replies (avatar + kind + name + npub).""" |
|
|
|
av = avatar_img_or_placeholder(parsed, 40, border_hex=border) |
|
|
|
|
|
|
|
name = html.escape(display_name_from_profile_or_hex(parsed, pubkey_hex)) |
|
|
|
|
|
|
|
npub_e = html.escape(npub_bech) |
|
|
|
|
|
|
|
pk_l = pubkey_hex.strip().lower() |
|
|
|
pk_l = pubkey_hex.strip().lower() |
|
|
|
href = html.escape(f"imwald://pub/{pk_l}", quote=True) |
|
|
|
href = html.escape(f"imwald://pub/{pk_l}", quote=True) |
|
|
|
|
|
|
|
av = avatar_img_or_placeholder(parsed, 40, border_hex=border, profile_href=href) |
|
|
|
|
|
|
|
name = html.escape(display_name_from_profile_or_hex(parsed, pubkey_hex)) |
|
|
|
|
|
|
|
npub_e = html.escape(npub_bech) |
|
|
|
inner = ( |
|
|
|
inner = ( |
|
|
|
'<div style="display:flex;align-items:center;gap:10px;margin:0 0 6px 0">' |
|
|
|
'<div style="display:flex;align-items:center;gap:10px;margin:0 0 6px 0">' |
|
|
|
f"{av}" |
|
|
|
f"{av}" |
|
|
|
@ -111,9 +121,20 @@ def inline_profile_badge_html(parsed: dict[str, str | None], pubkey_hex: str, np |
|
|
|
tip = html.escape(npub_tooltip) |
|
|
|
tip = html.escape(npub_tooltip) |
|
|
|
pic = safe_http_url(parsed.get("picture")) |
|
|
|
pic = safe_http_url(parsed.get("picture")) |
|
|
|
img = "" |
|
|
|
img = "" |
|
|
|
|
|
|
|
pk_l = pubkey_hex.strip().lower() |
|
|
|
|
|
|
|
prof_href = ( |
|
|
|
|
|
|
|
html.escape(f"imwald://pub/{pk_l}", quote=True) |
|
|
|
|
|
|
|
if len(pk_l) == 64 and all(c in "0123456789abcdef" for c in pk_l) |
|
|
|
|
|
|
|
else None |
|
|
|
|
|
|
|
) |
|
|
|
if pic: |
|
|
|
if pic: |
|
|
|
|
|
|
|
wrap = ( |
|
|
|
|
|
|
|
f'<a href="{prof_href}" title="View profile" style="text-decoration:none">' |
|
|
|
|
|
|
|
if prof_href |
|
|
|
|
|
|
|
else f'<a class="imwald-fullimg" href="{pic}" title="View full size" style="text-decoration:none">' |
|
|
|
|
|
|
|
) |
|
|
|
img = ( |
|
|
|
img = ( |
|
|
|
f'<a class="imwald-fullimg" href="{pic}" title="View full size" style="text-decoration:none">' |
|
|
|
f"{wrap}" |
|
|
|
f'<img src="{pic}" width="20" height="20" alt="" ' |
|
|
|
f'<img src="{pic}" width="20" height="20" alt="" ' |
|
|
|
'style="border-radius:50%;object-fit:cover;margin-right:6px;vertical-align:middle;flex-shrink:0">' |
|
|
|
'style="border-radius:50%;object-fit:cover;margin-right:6px;vertical-align:middle;flex-shrink:0">' |
|
|
|
"</a>" |
|
|
|
"</a>" |
|
|
|
@ -122,9 +143,20 @@ def inline_profile_badge_html(parsed: dict[str, str | None], pubkey_hex: str, np |
|
|
|
return f'<span class="nostr-user-badge" style="{badge_style}" title="{tip}">{inner}</span>' |
|
|
|
return f'<span class="nostr-user-badge" style="{badge_style}" title="{tip}">{inner}</span>' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def embed_author_row_html(parsed: dict[str, str | None], head_line_html: str) -> str: |
|
|
|
def embed_author_row_html( |
|
|
|
|
|
|
|
parsed: dict[str, str | None], |
|
|
|
|
|
|
|
head_line_html: str, |
|
|
|
|
|
|
|
*, |
|
|
|
|
|
|
|
pubkey_hex: str | None = None, |
|
|
|
|
|
|
|
) -> str: |
|
|
|
"""Avatar + headline row for embedded events.""" |
|
|
|
"""Avatar + headline row for embedded events.""" |
|
|
|
av = avatar_img_or_placeholder(parsed, 36, border_hex="#2a3d34") |
|
|
|
pk_l = (pubkey_hex or "").strip().lower() |
|
|
|
|
|
|
|
prof = ( |
|
|
|
|
|
|
|
html.escape(f"imwald://pub/{pk_l}", quote=True) |
|
|
|
|
|
|
|
if len(pk_l) == 64 and all(c in "0123456789abcdef" for c in pk_l) |
|
|
|
|
|
|
|
else None |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
av = avatar_img_or_placeholder(parsed, 36, border_hex="#2a3d34", profile_href=prof) |
|
|
|
return ( |
|
|
|
return ( |
|
|
|
'<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px">' |
|
|
|
'<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px">' |
|
|
|
f"{av}" |
|
|
|
f"{av}" |
|
|
|
|