diff --git a/src/components/ActivityFeed.tsx b/src/components/ActivityFeed.tsx index 1e42f3e..9c4dfce 100644 --- a/src/components/ActivityFeed.tsx +++ b/src/components/ActivityFeed.tsx @@ -5,6 +5,7 @@ import { formatDistanceToNow } from 'date-fns'; import { Skeleton } from '@/components/ui/skeleton'; import { MessageSquareText, Newspaper } from 'lucide-react'; import { AuthorDisplay } from './ui/author-display'; +import { LinkRenderer } from './ui/link-renderer'; interface FeedItemBase { id: string; @@ -135,7 +136,7 @@ const ActivityFeed: React.FC = () => { ) : (
- {item.content} +
↑ {item.voteCount} • Reply to post diff --git a/src/components/CommentCard.tsx b/src/components/CommentCard.tsx index 6b4225f..e6db1ae 100644 --- a/src/components/CommentCard.tsx +++ b/src/components/CommentCard.tsx @@ -11,6 +11,7 @@ import { import { Button } from '@/components/ui/button'; import { BookmarkButton } from '@/components/ui/bookmark-button'; import { AuthorDisplay } from '@/components/ui/author-display'; +import { LinkRenderer } from '@/components/ui/link-renderer'; import { usePending, usePendingVote } from '@/hooks/usePending'; import { Tooltip, @@ -132,7 +133,9 @@ const CommentCard: React.FC = ({ />
-

{comment.content}

+

+ +

{canModerate && !comment.moderated && ( diff --git a/src/components/PostCard.tsx b/src/components/PostCard.tsx index e290222..139ce63 100644 --- a/src/components/PostCard.tsx +++ b/src/components/PostCard.tsx @@ -13,6 +13,7 @@ import { import { RelevanceIndicator } from '@/components/ui/relevance-indicator'; import { AuthorDisplay } from '@/components/ui/author-display'; import { BookmarkButton } from '@/components/ui/bookmark-button'; +import { LinkRenderer } from '@/components/ui/link-renderer'; import { usePending, usePendingVote } from '@/hooks/usePending'; import { useToast } from '@/components/ui/use-toast'; @@ -187,7 +188,7 @@ const PostCard: React.FC = ({ post, commentCount = 0 }) => { {/* Post content preview */}

- {contentPreview} +

{/* Post actions */} diff --git a/src/components/PostDetail.tsx b/src/components/PostDetail.tsx index 79e3364..ab7350c 100644 --- a/src/components/PostDetail.tsx +++ b/src/components/PostDetail.tsx @@ -24,6 +24,7 @@ import { formatDistanceToNow } from 'date-fns'; import { RelevanceIndicator } from './ui/relevance-indicator'; import { AuthorDisplay } from './ui/author-display'; import { BookmarkButton } from './ui/bookmark-button'; +import { LinkRenderer } from './ui/link-renderer'; import CommentCard from './CommentCard'; import { usePending, usePendingVote } from '@/hooks/usePending'; @@ -236,7 +237,7 @@ const PostDetail = () => { />

- {post.content} +

diff --git a/src/components/PostList.tsx b/src/components/PostList.tsx index a613efc..3ced109 100644 --- a/src/components/PostList.tsx +++ b/src/components/PostList.tsx @@ -13,6 +13,7 @@ import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Skeleton } from '@/components/ui/skeleton'; +import { LinkRenderer } from '@/components/ui/link-renderer'; import { ArrowLeft, MessageSquare, @@ -300,7 +301,9 @@ const PostList = () => {

{post.title}

-

{post.content}

+

+ +

{formatDistanceToNow(post.timestamp, { diff --git a/src/components/ui/link-renderer.tsx b/src/components/ui/link-renderer.tsx new file mode 100644 index 0000000..71c6e4a --- /dev/null +++ b/src/components/ui/link-renderer.tsx @@ -0,0 +1,43 @@ +import React from 'react'; + +interface LinkRendererProps { + text: string; + className?: string; +} + +/** + * Component that renders text with clickable links + * Detects URLs and converts them to clickable tags + */ +export const LinkRenderer: React.FC = ({ text, className }) => { + // URL regex pattern that matches http/https URLs + const urlRegex = /(https?:\/\/[^\s]+)/g; + + // Split text by URLs and create array of text segments and URLs + const parts = text.split(urlRegex); + + return ( + + {parts.map((part, index) => { + // Check if this part is a URL + if (urlRegex.test(part)) { + return ( + + {part} + + ); + } + // Regular text + return part; + })} + + ); +}; + +export default LinkRenderer;