69 lines
2.6 KiB
TypeScript
69 lines
2.6 KiB
TypeScript
import type { PinnedMessage } from '@chat-app/shared/chat';
|
|
|
|
import { PinIcon, XIcon } from './icons';
|
|
|
|
interface Props {
|
|
open: boolean;
|
|
pins: PinnedMessage[];
|
|
onClose: () => void;
|
|
onJump: (messageId: string) => void;
|
|
onUnpin: (messageId: string) => void;
|
|
// Optional preview-renderer: parent resolves messageId → short text/snippet
|
|
// since the panel itself doesn't decrypt. If absent, the panel just shows
|
|
// the message-id stub.
|
|
renderPreview?: (messageId: string) => React.ReactNode;
|
|
}
|
|
|
|
export function PinnedMessagesPanel({ open, pins, onClose, onJump, onUnpin, renderPreview }: Props) {
|
|
if (!open) return null;
|
|
return (
|
|
<aside
|
|
role="complementary"
|
|
aria-label="Angepinnte Nachrichten"
|
|
className="absolute right-0 top-0 z-30 flex h-full w-80 flex-col border-l border-line bg-surface-2 shadow-xl"
|
|
>
|
|
<header className="flex items-center justify-between border-b border-line px-4 py-3">
|
|
<div className="flex items-center gap-2">
|
|
<PinIcon className="h-4 w-4 text-accent" />
|
|
<h3 className="text-sm font-semibold text-fg">Angepinnt · {pins.length}</h3>
|
|
</div>
|
|
<button
|
|
type="button"
|
|
onClick={onClose}
|
|
aria-label="Schließen"
|
|
className="flex h-7 w-7 cursor-pointer items-center justify-center rounded-md text-fg-muted hover:bg-surface-3 hover:text-fg"
|
|
>
|
|
<XIcon className="h-4 w-4" />
|
|
</button>
|
|
</header>
|
|
{pins.length === 0 ? (
|
|
<p className="p-6 text-center text-xs text-fg-muted">Noch nichts angepinnt.</p>
|
|
) : (
|
|
<ul className="flex-1 overflow-y-auto">
|
|
{pins.map((p) => (
|
|
<li key={p.messageId} className="border-b border-line/60 px-4 py-3">
|
|
<button
|
|
type="button"
|
|
onClick={() => onJump(p.messageId)}
|
|
className="block w-full cursor-pointer text-left text-sm text-fg hover:text-accent"
|
|
>
|
|
{renderPreview ? renderPreview(p.messageId) : <span className="font-mono text-xs">{p.messageId.slice(0, 8)}</span>}
|
|
</button>
|
|
<div className="mt-1 flex items-center justify-between text-[11px] text-fg-muted">
|
|
<time dateTime={p.pinnedAt}>{new Date(p.pinnedAt).toLocaleString()}</time>
|
|
<button
|
|
type="button"
|
|
onClick={() => onUnpin(p.messageId)}
|
|
className="cursor-pointer text-rose-400 hover:underline"
|
|
>
|
|
Anheftung entfernen
|
|
</button>
|
|
</div>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
</aside>
|
|
);
|
|
}
|