added features and fixes

This commit is contained in:
2026-07-02 15:34:00 +00:00
parent eb5b7d55a4
commit 89f8381e2d
30 changed files with 1718 additions and 206 deletions
+89
View File
@@ -0,0 +1,89 @@
import { useEffect } from "react";
import { useMessageStore } from "../stores/message.ts";
interface PinnedMessagesProps {
channelId: string;
channelName: string;
onClose: () => void;
onJump?: (messageId: string) => void;
}
export function PinnedMessages({ channelId, channelName, onClose, onJump }: PinnedMessagesProps) {
const pinnedMessages = useMessageStore((s) => s.pinnedMessagesByChannel[channelId] || []);
const fetchPinnedMessages = useMessageStore((s) => s.fetchPinnedMessages);
const unpinMessage = useMessageStore((s) => s.unpinMessage);
useEffect(() => {
fetchPinnedMessages(channelId);
}, [channelId, fetchPinnedMessages]);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if (e.key === "Escape") {
onClose();
}
};
window.addEventListener("keydown", handler);
return () => window.removeEventListener("keydown", handler);
}, [onClose]);
return (
<div className="absolute inset-x-0 top-0 z-20 bg-gb-bg border-b border-gb-bg-t shadow-lg">
<div className="px-3 py-2 border-b border-gb-bg-t flex items-center justify-between">
<span className="text-xs text-gb-orange font-mono">PINNED IN #{channelName.toUpperCase()} ({pinnedMessages.length}/5)</span>
<button onClick={onClose} className="text-xs text-gb-red hover:text-gb-orange">[x]</button>
</div>
<div className="max-h-64 overflow-y-auto font-mono text-xs">
{pinnedMessages.length === 0 ? (
<div className="px-3 py-4 text-center text-gb-fg-f">[no pinned messages in this channel]</div>
) : (
pinnedMessages.map((msg) => (
<div
key={msg.id}
className="w-full text-left px-3 py-2 border-b border-gb-bg-t last:border-b-0 hover:bg-gb-bg-s/20 flex flex-col gap-1"
>
<div className="flex items-center justify-between text-gb-fg-f">
<div className="flex items-center gap-2">
<span className="text-gb-aqua font-bold">&lt;{msg.author_username}&gt;</span>
<span className="text-[10px] text-gb-fg-f">
{new Date(msg.created_at).toLocaleString()}
</span>
</div>
<div className="flex items-center gap-2">
{onJump && (
<button
onClick={() => {
onJump(msg.id);
onClose();
}}
className="text-gb-aqua hover:text-gb-orange"
title="Jump to message"
>
[JUMP]
</button>
)}
<button
onClick={async () => {
if (confirm("Unpin this message?")) {
try {
await unpinMessage(channelId, msg.id);
} catch (err) {
alert(err instanceof Error ? err.message : "Failed to unpin");
}
}
}}
className="text-gb-red hover:text-gb-orange"
title="Unpin message"
>
[UNPIN]
</button>
</div>
</div>
<div className="text-gb-fg break-words whitespace-pre-wrap">{msg.content}</div>
</div>
))
)}
</div>
</div>
);
}