Skip to content
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 66 additions & 2 deletions components/compose/compose-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import { usePlatformDetection } from '@/hooks/use-platform-detection'
import { UserAvatar } from '@/components/ui/avatar-image'
import { extractAllTags, extractMentions } from '@/lib/post-helpers'
import { extractFirstUrl, isDirectImageUrl, stripTrailingPunctuation } from '@/hooks/use-link-preview'
import { LinkIcon } from '@heroicons/react/24/outline'

Check failure on line 25 in components/compose/compose-modal.tsx

View workflow job for this annotation

GitHub Actions / Type Check

Duplicate identifier 'LinkIcon'.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
import { hashtagService } from '@/lib/services/hashtag-service'
import { mentionService } from '@/lib/services/mention-service'
import { extractErrorMessage, isTimeoutError, categorizeError } from '@/lib/error-utils'
Expand All @@ -37,7 +39,7 @@
getDialogDescription,
} from './compose-sub-components'
import { VisibilitySelector, TEASER_LIMIT } from './visibility-selector'
import { LockClosedIcon, LinkIcon } from '@heroicons/react/24/solid'

Check failure on line 42 in components/compose/compose-modal.tsx

View workflow job for this annotation

GitHub Actions / Type Check

Duplicate identifier 'LinkIcon'.
import { isPrivatePost } from '@/components/post/private-post-content'
import type { EncryptionSource } from '@/lib/services/post-service'
import { AddEncryptionKeyModal } from '@/components/auth/add-encryption-key-modal'
Expand Down Expand Up @@ -388,13 +390,75 @@

{/* Content area */}
{showPreview || isPosted ? (
<div className={`min-h-[60px] whitespace-pre-wrap break-words ${
<div className={`min-h-[60px] ${
isPosted
? 'text-gray-600 dark:text-gray-400'
: 'text-gray-900 dark:text-gray-100'
}`}>
{post.content ? (
<MarkdownContent content={post.content} />
(() => {
const firstUrl = extractFirstUrl(post.content)
const isImageUrl = firstUrl && isDirectImageUrl(firstUrl)

// Strip the image URL from content (matching PostContent behavior)
let displayContent = post.content
if (isImageUrl && firstUrl) {
// Remove the URL but keep any trailing punctuation
const cleanUrl = stripTrailingPunctuation(firstUrl)
displayContent = post.content.replace(cleanUrl, '').trim()
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// Extract hostname for footer
const hostname = isImageUrl && firstUrl ? (() => {
try {
return new URL(firstUrl).hostname.replace(/^www\./, '')
} catch {
return firstUrl
}
})() : null

return (
<>
{displayContent && (
<div className="whitespace-pre-wrap break-words">
<MarkdownContent content={displayContent} />
</div>
)}
{/* Image preview matching LinkPreview component exactly */}
{isImageUrl && firstUrl && (
<div className="mt-3">
<a
href={firstUrl}
target="_blank"
rel="noopener noreferrer"
onClick={(e) => e.stopPropagation()}
className="block border border-neutral-200 dark:border-neutral-700 rounded-xl overflow-hidden hover:bg-neutral-50 dark:hover:bg-neutral-800/50 transition-colors"
>
<div className="relative bg-neutral-100 dark:bg-neutral-800">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={firstUrl}
alt="Image preview"
className="w-full max-h-[400px] object-contain"
onError={(e) => {
const parent = e.currentTarget.parentElement
if (parent) {
parent.innerHTML = '<div class="flex items-center justify-center h-32 text-neutral-400">Failed to load image</div>'
}
}}
/>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
</div>
{/* Domain info footer */}
<div className="flex items-center gap-1.5 px-3 py-2 text-xs text-neutral-500 dark:text-neutral-400 border-t border-neutral-200 dark:border-neutral-700">
<LinkIcon className="h-3.5 w-3.5 flex-shrink-0" />
<span className="truncate">{hostname}</span>
</div>
</a>
</div>
)}
</>
)
})()
) : (
<span className="text-gray-400 dark:text-gray-600 italic">
Nothing to preview
Expand Down
Loading