feat(chat): Make URLs in AI responses clickable

- Add linkifyText() function to convert URLs to anchor tags
- Apply linkification only to assistant messages (safe XSS handling)
- Add CSS styling for links: blue color, underline, hover effect
- Links open in new tab with noopener noreferrer

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-01-13 13:36:55 +01:00
parent 0050cd1fdf
commit a5c8e9b585

View File

@ -145,6 +145,17 @@
border: 1px solid var(--border);
}
.message.assistant .message-content a {
color: var(--primary);
text-decoration: underline;
word-break: break-all;
}
.message.assistant .message-content a:hover {
color: var(--primary-dark, #1e40af);
text-decoration: none;
}
.message-meta {
font-size: var(--font-size-sm);
color: var(--text-secondary);
@ -703,6 +714,24 @@
}
}
// Convert URLs in text to clickable links
function linkifyText(text) {
// First escape HTML to prevent XSS
const escaped = text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
// Then convert URLs to links
// Match http://, https://, and www. URLs
const urlRegex = /(https?:\/\/[^\s<]+|www\.[^\s<]+)/gi;
return escaped.replace(urlRegex, function(url) {
const href = url.startsWith('www.') ? 'https://' + url : url;
return `<a href="${href}" target="_blank" rel="noopener noreferrer">${url}</a>`;
});
}
// Add message to UI
function addMessage(role, content, messageId = null, techInfo = null) {
const messageDiv = document.createElement('div');
@ -716,7 +745,12 @@
const contentDiv = document.createElement('div');
contentDiv.className = 'message-content';
contentDiv.textContent = content;
// Use innerHTML with linkified text for assistant messages (URLs become clickable)
if (role === 'assistant') {
contentDiv.innerHTML = linkifyText(content);
} else {
contentDiv.textContent = content;
}
contentWrapper.appendChild(contentDiv);
// Add feedback buttons for assistant messages