UNPKG

@medalsocial/meda

Version:

Shared Meda UI shell and runtime package.

45 lines (44 loc) 5.67 kB
'use client'; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { Eye, Pin, Share2 } from 'lucide-react'; import { cn } from '../../lib/utils.js'; import { Avatar } from '../internal/avatar.js'; import { Textarea } from '../internal/textarea.js'; export const DEFAULT_TELEGRAM_LABELS = { placeholder: 'Type a message...', pinnedMessage: 'Pinned message', share: 'Share', buttonFallback: 'Button', pollOptionPlaceholder: (number) => `Option ${number}`, }; /** * Telegram channel post preview. Renders a chat bubble with optional * poll, pinned indicator, and inline keyboard. */ export function TelegramPreview({ displayName, username: _username, avatarUrl, content, mediaUrls, editable = false, onContentChange, className, labels, poll, pinMessage, replyMarkup, }) { const l = { ...DEFAULT_TELEGRAM_LABELS, ...labels }; return (_jsx("div", { "data-slot": "post-preview", "data-platform": "telegram", className: cn('@container min-h-[200px] bg-[#E7EBF0] p-4 text-gray-900 @[420px]:p-5', className), children: _jsxs("div", { className: "max-w-md", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(Avatar, { src: avatarUrl, displayName: displayName, className: "h-8 w-8" }), _jsx("span", { className: "font-medium text-[14px] text-[#168ACD]", children: displayName })] }), _jsxs("div", { className: "overflow-hidden rounded-xl rounded-tl-sm bg-white shadow-sm", children: [pinMessage ? (_jsxs("div", { "data-slot": "telegram-pinned", className: "flex items-center gap-1 border-gray-200 border-b px-3 py-2 text-[11px] text-gray-500", children: [_jsx(Pin, { className: "h-3 w-3", "aria-hidden": "true" }), _jsx("span", { children: l.pinnedMessage })] })) : null, mediaUrls && mediaUrls.length > 0 && (_jsx("div", { className: cn(mediaUrls.length === 1 && 'aspect-video', mediaUrls.length >= 2 && 'grid grid-cols-2 gap-0.5'), children: mediaUrls.slice(0, 4).map((url, i) => (_jsx("div", { className: cn('bg-gray-100', mediaUrls.length === 1 && 'aspect-video', mediaUrls.length >= 2 && 'aspect-square'), children: _jsx("img", { src: url, alt: `Media ${i + 1}`, loading: "lazy", decoding: "async", className: "h-full w-full object-cover" }) }, url))) })), _jsxs("div", { className: "p-3", children: [renderBody({ poll, editable, content, onContentChange, labels: l }), replyMarkup?.inline_keyboard?.length ? (_jsx("div", { className: "mt-3 space-y-1", children: replyMarkup.inline_keyboard.map((row) => { const rowKey = row .map((b) => `${b.text}|${b.url ?? b.callbackData ?? ''}`) .join('::'); return (_jsx("div", { className: "flex gap-1", children: row.map((button) => (_jsx("a", { href: button.url ?? '#', target: "_blank", rel: "noreferrer", className: "flex-1 rounded bg-[#168ACD] px-3 py-1.5 text-center text-white text-xs", children: button.text || l.buttonFallback }, `${button.text}-${button.url ?? button.callbackData ?? ''}`))) }, rowKey)); }) })) : null, _jsxs("div", { className: "mt-2 flex items-center justify-end gap-1 text-[12px] text-gray-500", children: [_jsx(Eye, { className: "h-3 w-3", "aria-hidden": "true" }), _jsx("span", { children: "0" }), _jsx("span", { className: "ml-2", children: "12:00" })] })] })] }), _jsxs("div", { className: "mt-2 flex items-center gap-2", children: [_jsxs("button", { type: "button", className: "inline-flex min-h-11 items-center gap-1 rounded-full bg-white px-3 py-1 text-[13px] shadow-sm", children: [_jsx("span", { "aria-hidden": "true", children: "\uD83D\uDC4D" }), _jsx("span", { className: "text-gray-500", children: "0" })] }), _jsxs("button", { type: "button", className: "inline-flex min-h-11 items-center gap-1 rounded-full bg-white px-3 py-1 text-[13px] shadow-sm", children: [_jsx("span", { "aria-hidden": "true", children: "\u2764\uFE0F" }), _jsx("span", { className: "text-gray-500", children: "0" })] }), _jsx("button", { type: "button", "aria-label": l.share, className: "inline-flex min-h-11 min-w-11 items-center justify-center rounded-full bg-white p-1.5 shadow-sm", children: _jsx(Share2, { className: "h-4 w-4 text-gray-500" }) })] })] }) })); } /* v8 ignore next 13 — v8 phantom duplicate function record */ function renderBody({ poll, editable, content, onContentChange, labels, }) { /* v8 ignore next 2 — v8 phantom duplicate if-statement and its consequent */ if (poll) { return (_jsxs("div", { "data-slot": "telegram-poll", className: "space-y-2", children: [_jsx("p", { className: "font-medium", children: poll.question }), poll.options.map((option, index) => { // Options can repeat / be empty during composing; combine with stable index in a non-positional way // by counting prior empties so the key remains unique without leaking positional intent. const key = option ? `opt-${option}` : `placeholder-${labels.pollOptionPlaceholder(index + 1)}`; return (_jsx("div", { className: "rounded bg-gray-50 px-3 py-2 text-sm", children: option || labels.pollOptionPlaceholder(index + 1) }, key)); })] })); } if (editable) { return (_jsx(Textarea, { value: content, onChange: (e) => onContentChange?.(e.target.value), placeholder: labels.placeholder, className: "min-h-[60px] text-[15px] placeholder:text-gray-500" })); } return _jsx("p", { className: "whitespace-pre-wrap break-words text-[15px]", children: content }); }