reply UX: show username + content preview instead of hash

- ComposeBox takes ReplyContext {id, username, content} instead of string
- Reply chip shows "^ benji message preview..." with truncation
- App passes full reply context from messagesById

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 21:14:35 +02:00
parent c0f48c5672
commit 1f9201dd03
2 changed files with 18 additions and 6 deletions

View File

@@ -43,7 +43,7 @@ export default function App() {
const [activeChannelId, setActiveChannelId] = useState<string | null>(null);
const [messages, setMessages] = useState<Message[]>([]);
const [loading, setLoading] = useState(false);
const [replyTo, setReplyTo] = useState<string | null>(null);
const [replyTo, setReplyTo] = useState<{ id: string; username: string; content: string } | null>(null);
const [sheetOpen, setSheetOpen] = useState(false);
const scrollRef = useRef<HTMLDivElement>(null);
const prevMsgCountRef = useRef(0);
@@ -178,7 +178,12 @@ export default function App() {
key={msg.id}
message={msg}
replyTarget={msg.reply_to ? messagesById.get(msg.reply_to) : undefined}
onReply={setReplyTo}
onReply={(id) => {
const target = messagesById.get(id);
if (target) {
setReplyTo({ id, username: target.user.display_name, content: target.content });
}
}}
/>
))
)}

View File

@@ -4,9 +4,15 @@ import type { User } from "@/types/User";
import { postMessage, getUsers, getCurrentUsername } from "@/api";
import { cn } from "@/lib/utils";
interface ReplyContext {
id: string;
username: string;
content: string;
}
interface Props {
channelId: string;
replyTo: string | null;
replyTo: ReplyContext | null;
onClearReply: () => void;
onMessageSent: () => void;
}
@@ -95,7 +101,7 @@ export function ComposeBox({
await postMessage(channelId, {
content: content.trim(),
type: msgType,
reply_to: replyTo ?? undefined,
reply_to: replyTo?.id ?? undefined,
});
setContent("");
setMsgType("text");
@@ -122,11 +128,12 @@ export function ComposeBox({
{replyTo && (
<div className="flex items-center gap-1.5 mb-1.5 text-[10px] font-mono">
<span className="text-primary">^</span>
<span className="text-muted-foreground">#{replyTo.slice(0, 8)}</span>
<span className="text-foreground font-bold">{replyTo.username}</span>
<span className="text-muted-foreground truncate max-w-48 md:max-w-96">{replyTo.content}</span>
<button
type="button"
onClick={onClearReply}
className="text-muted-foreground hover:text-primary ml-1"
className="text-muted-foreground hover:text-primary ml-auto flex-shrink-0"
>
x
</button>