mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-12 11:43:03 +02:00
Add mention highlighting
This commit is contained in:
+24
-24
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -4,8 +4,8 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>RemoteTerm for MeshCore</title>
|
<title>RemoteTerm for MeshCore</title>
|
||||||
<script type="module" crossorigin src="/assets/index-DycUwj3W.js"></script>
|
<script type="module" crossorigin src="/assets/index-BHdy0kQg.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-C3_XTTUI.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CtV9BARe.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -816,6 +816,7 @@ export function App() {
|
|||||||
hasOlderMessages={hasOlderMessages}
|
hasOlderMessages={hasOlderMessages}
|
||||||
onSenderClick={activeConversation.type === 'channel' ? handleSenderClick : undefined}
|
onSenderClick={activeConversation.type === 'channel' ? handleSenderClick : undefined}
|
||||||
onLoadOlder={fetchOlderMessages}
|
onLoadOlder={fetchOlderMessages}
|
||||||
|
radioName={config?.name}
|
||||||
/>
|
/>
|
||||||
<MessageInput
|
<MessageInput
|
||||||
ref={messageInputRef}
|
ref={messageInputRef}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useLayoutEffect, useRef, useCallback, useState } from 'react';
|
import { useEffect, useLayoutEffect, useRef, useCallback, useState, type ReactNode } from 'react';
|
||||||
import type { Contact, Message } from '../types';
|
import type { Contact, Message } from '../types';
|
||||||
import { formatTime, parseSenderFromText } from '../utils/messageParser';
|
import { formatTime, parseSenderFromText } from '../utils/messageParser';
|
||||||
import { pubkeysMatch } from '../utils/pubkey';
|
import { pubkeysMatch } from '../utils/pubkey';
|
||||||
@@ -13,6 +13,51 @@ interface MessageListProps {
|
|||||||
hasOlderMessages?: boolean;
|
hasOlderMessages?: boolean;
|
||||||
onSenderClick?: (sender: string) => void;
|
onSenderClick?: (sender: string) => void;
|
||||||
onLoadOlder?: () => void;
|
onLoadOlder?: () => void;
|
||||||
|
radioName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to render text with highlighted @[Name] mentions
|
||||||
|
function renderTextWithMentions(text: string, radioName?: string): ReactNode {
|
||||||
|
if (!radioName) return text;
|
||||||
|
|
||||||
|
const mentionPattern = /@\[([^\]]+)\]/g;
|
||||||
|
const parts: ReactNode[] = [];
|
||||||
|
let lastIndex = 0;
|
||||||
|
let match: RegExpExecArray | null;
|
||||||
|
let keyIndex = 0;
|
||||||
|
|
||||||
|
while ((match = mentionPattern.exec(text)) !== null) {
|
||||||
|
// Add text before the match
|
||||||
|
if (match.index > lastIndex) {
|
||||||
|
parts.push(text.slice(lastIndex, match.index));
|
||||||
|
}
|
||||||
|
|
||||||
|
const mentionedName = match[1];
|
||||||
|
const isOwnMention = mentionedName === radioName;
|
||||||
|
|
||||||
|
parts.push(
|
||||||
|
<span
|
||||||
|
key={keyIndex++}
|
||||||
|
className={cn(
|
||||||
|
"rounded px-0.5",
|
||||||
|
isOwnMention
|
||||||
|
? "bg-primary/30 text-primary font-medium"
|
||||||
|
: "bg-muted-foreground/20"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
@[{mentionedName}]
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
lastIndex = match.index + match[0].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add remaining text after last match
|
||||||
|
if (lastIndex < text.length) {
|
||||||
|
parts.push(text.slice(lastIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.length > 0 ? parts : text;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MessageList({
|
export function MessageList({
|
||||||
@@ -23,6 +68,7 @@ export function MessageList({
|
|||||||
hasOlderMessages = false,
|
hasOlderMessages = false,
|
||||||
onSenderClick,
|
onSenderClick,
|
||||||
onLoadOlder,
|
onLoadOlder,
|
||||||
|
radioName,
|
||||||
}: MessageListProps) {
|
}: MessageListProps) {
|
||||||
const listRef = useRef<HTMLDivElement>(null);
|
const listRef = useRef<HTMLDivElement>(null);
|
||||||
const prevMessagesLengthRef = useRef<number>(0);
|
const prevMessagesLengthRef = useRef<number>(0);
|
||||||
@@ -234,7 +280,7 @@ export function MessageList({
|
|||||||
<div className="break-words whitespace-pre-wrap">
|
<div className="break-words whitespace-pre-wrap">
|
||||||
{content.split('\n').map((line, i, arr) => (
|
{content.split('\n').map((line, i, arr) => (
|
||||||
<span key={i}>
|
<span key={i}>
|
||||||
{line}
|
{renderTextWithMentions(line, radioName)}
|
||||||
{i < arr.length - 1 && <br />}
|
{i < arr.length - 1 && <br />}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user