From a65125a23983013b0067e2214ec261f818a2a961 Mon Sep 17 00:00:00 2001 From: dmitriylaukhin Date: Wed, 27 May 2026 14:16:25 +0500 Subject: [PATCH] Linkify URLs and preserve line breaks in question messages --- .../questions/QuestionSplitView.tsx | 3 ++- src/components/questions/QuestionThread.tsx | 3 ++- src/lib/linkify.tsx | 26 +++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 src/lib/linkify.tsx diff --git a/src/components/questions/QuestionSplitView.tsx b/src/components/questions/QuestionSplitView.tsx index 235ee96..0d5cf30 100644 --- a/src/components/questions/QuestionSplitView.tsx +++ b/src/components/questions/QuestionSplitView.tsx @@ -1,6 +1,7 @@ "use client"; import { useState, useEffect, useCallback, useRef } from "react"; +import { linkify } from "@/lib/linkify"; interface FileAttachment { name: string; @@ -322,7 +323,7 @@ export function QuestionSplitView({ currentUserId }: { currentUserId: string })

{msg.author.name} · {formatDate(msg.createdAt)}

-

{msg.text}

+

{linkify(msg.text)}

{msg.files && msg.files.length > 0 && (
{msg.files.map((f) => ( diff --git a/src/components/questions/QuestionThread.tsx b/src/components/questions/QuestionThread.tsx index e10edc0..d923ea2 100644 --- a/src/components/questions/QuestionThread.tsx +++ b/src/components/questions/QuestionThread.tsx @@ -1,6 +1,7 @@ "use client"; import { useState, useRef, useEffect } from "react"; +import { linkify } from "@/lib/linkify"; interface FileAttachment { name: string; @@ -140,7 +141,7 @@ export function QuestionThread({ · 🔵 новое )}

-

{msg.text}

+

{linkify(msg.text)}

{msg.files && msg.files.length > 0 && (
{msg.files.map((f, i) => ( diff --git a/src/lib/linkify.tsx b/src/lib/linkify.tsx new file mode 100644 index 0000000..1a56668 --- /dev/null +++ b/src/lib/linkify.tsx @@ -0,0 +1,26 @@ +import { Fragment, type ReactNode } from "react"; + +const URL_RE = /(https?:\/\/[^\s<>()]+[^\s<>().,;:!?])/g; + +export function linkify(text: string): ReactNode[] { + if (!text) return []; + const parts = text.split(URL_RE); + return parts.map((part, i) => { + if (URL_RE.test(part)) { + URL_RE.lastIndex = 0; + return ( + + {part} + + ); + } + return {part}; + }); +}