diff --git a/src/app.css b/src/app.css index 5b2e466..de520b5 100644 --- a/src/app.css +++ b/src/app.css @@ -472,7 +472,8 @@ img.emoji-inline { } /* Responsive images and media - max 600px, scale down on smaller screens */ -img:not(.profile-picture):not([alt*="profile" i]):not([alt*="avatar" i]):not([src*="avatar" i]):not([src*="profile" i]):not(.relay-icon):not(.relay-favorite-pic), +/* Exclude profile pictures, avatars, and emoji images from responsive sizing */ +img:not(.profile-picture):not([alt*="profile" i]):not([alt*="avatar" i]):not([src*="avatar" i]):not([src*="profile" i]):not(.relay-icon):not(.relay-favorite-pic):not(.emoji-inline):not(.avatar), video, audio { max-width: 600px !important; @@ -482,10 +483,11 @@ audio { } /* Ensure media in markdown content is responsive */ -.markdown-content img, +/* Exclude profile pictures, avatars, and emoji images from responsive sizing - they should maintain their fixed size */ +.markdown-content img:not(.profile-picture):not([class*="profile"]):not(.emoji-inline):not(.avatar), .markdown-content video, .markdown-content audio, -.post-content img, +.post-content img:not(.profile-picture):not([class*="profile"]):not(.emoji-inline):not(.avatar), .post-content video, .post-content audio { max-width: 600px; @@ -494,6 +496,22 @@ audio { display: block; } +/* Ensure avatars in mentions autocomplete are not affected by responsive image styles */ +.mentions-autocomplete img.avatar, +.mentions-autocomplete .avatar { + width: 1.25rem !important; + height: 1.25rem !important; + min-width: 1.25rem !important; + min-height: 1.25rem !important; + max-width: 1.25rem !important; + max-height: 1.25rem !important; + aspect-ratio: 1 / 1 !important; + border-radius: 50% !important; + object-fit: cover !important; + flex-shrink: 0 !important; + display: block !important; +} + /* Media gallery items should also be responsive */ .media-gallery img, .media-gallery video { diff --git a/src/lib/components/content/MarkdownRenderer.svelte b/src/lib/components/content/MarkdownRenderer.svelte index 472d2dc..07c5760 100644 --- a/src/lib/components/content/MarkdownRenderer.svelte +++ b/src/lib/components/content/MarkdownRenderer.svelte @@ -1037,6 +1037,21 @@ align-items: center; } + /* Ensure profile pictures in markdown content maintain circular shape and don't stretch */ + :global(.markdown-content .profile-badge .profile-picture), + :global(.markdown-content .profile-badge .profile-placeholder) { + width: 1.5rem !important; + height: 1.5rem !important; + max-width: 1.5rem !important; + max-height: 1.5rem !important; + min-width: 1.5rem !important; + min-height: 1.5rem !important; + aspect-ratio: 1 / 1 !important; + border-radius: 50% !important; + object-fit: cover !important; + flex-shrink: 0 !important; + } + /* Embedded events should be block-level */ :global(.markdown-content [data-nostr-event]) { display: block; diff --git a/src/lib/components/content/MentionsAutocomplete.svelte b/src/lib/components/content/MentionsAutocomplete.svelte index 8c15bef..90c24b9 100644 --- a/src/lib/components/content/MentionsAutocomplete.svelte +++ b/src/lib/components/content/MentionsAutocomplete.svelte @@ -26,29 +26,36 @@ const cursorPos = target.selectionStart || 0; // Find @ mention starting from cursor backwards - // Allow word chars, @, dots, and hyphens to support NIP-05 format (user@domain.com) + // We need to find the leftmost @ that could start a mention let start = cursorPos - 1; + let foundAt = -1; + + // First, find the leftmost @ going backwards while characters are valid mention chars + // This handles cases like @user@domain.com - we want the first @ while (start >= 0 && /[\w@.-]/.test(text[start])) { + if (text[start] === '@') { + foundAt = start; + } start--; } - if (start >= 0 && text[start] === '@') { - // Found @ mention - mentionStart = start; - const mentionText = text.substring(start + 1, cursorPos); + // If we found an @ and there's valid mention text after it, show suggestions + if (foundAt >= 0) { + mentionStart = foundAt; + const mentionText = text.substring(foundAt + 1, cursorPos); // Check if we're still in a valid mention (word chars, @, dots, hyphens) // Support both simple handles (@user) and NIP-05 format (@user@domain.com) if (mentionText.length > 0 && /^[\w.-]+(@[\w.-]+)?$/.test(mentionText)) { query = mentionText; updateSuggestions(mentionText); - updatePosition(target, start); + updatePosition(target, foundAt); showSuggestions = true; } else if (mentionText.length === 0) { // Just @, show all suggestions query = ''; updateSuggestions(''); - updatePosition(target, start); + updatePosition(target, foundAt); showSuggestions = true; } else { showSuggestions = false; @@ -132,9 +139,21 @@ const suggestion = suggestions[index]; const handle = suggestion.handle || suggestion.name || suggestion.pubkey.slice(0, 8); - const mentionText = `@${handle} `; - // Replace @mention with selected handle + // Convert pubkey to npub format (NIP-19) + let npub: string; + try { + npub = nip19.npubEncode(suggestion.pubkey); + } catch (error) { + console.error('Error encoding pubkey to npub:', error); + // Fallback to @handle if encoding fails + npub = suggestion.pubkey; + } + + // Insert as nostr:npub... format instead of @handle + const mentionText = `nostr:${npub} `; + + // Replace @mention with nostr:npub format const text = textarea.value; const cursorPos = textarea.selectionStart || 0; const textBefore = text.substring(0, mentionStart); @@ -186,6 +205,7 @@ src={suggestion.picture} alt="" class="avatar" + style="width: 1.25rem; height: 1.25rem; min-width: 1.25rem; min-height: 1.25rem; max-width: 1.25rem; max-height: 1.25rem; aspect-ratio: 1 / 1; border-radius: 50%; object-fit: cover; flex-shrink: 0; display: block;" onerror={(e) => { (e.target as HTMLImageElement).style.display = 'none'; }} @@ -197,7 +217,9 @@