global update and global fix

This commit is contained in:
lendry
2026-06-25 23:48:57 +03:00
parent 3880c68d59
commit b0ea87e898
121 changed files with 13759 additions and 663 deletions

View File

@@ -0,0 +1,173 @@
'use client';
import { CheckCircle2, Copy, Forward, Pencil, Reply, Trash2 } from 'lucide-react';
import { ChatMessageReactions } from '@/components/chat/chat-message-reactions';
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuTrigger
} from '@/components/ui/context-menu';
import type { ChatMessage } from '@/lib/api';
import { QUICK_REACTIONS, canDeleteMessage, canEditMessage, getMessageCopyText } from '@/lib/chat-message-utils';
import { cn } from '@/lib/utils';
interface ChatMessageContextMenuProps {
message: ChatMessage;
userId?: string;
isE2E?: boolean;
visibleText?: string;
children: React.ReactNode;
onEdit?: () => void;
onDelete?: () => void;
onReply?: () => void;
onForward?: () => void;
onSelect?: () => void;
onToggleReaction?: (emoji: string) => void;
onCopy?: () => void;
}
export function ChatMessageContextMenu({
message,
userId,
isE2E,
visibleText,
children,
onEdit,
onDelete,
onReply,
onForward,
onSelect,
onToggleReaction,
onCopy
}: ChatMessageContextMenuProps) {
const editable = canEditMessage(message, userId, isE2E);
const deletable = canDeleteMessage(message, userId);
const copyText = getMessageCopyText(message, visibleText);
const disabled = message.isDeleted;
return (
<ContextMenu>
<ContextMenuTrigger asChild>{children}</ContextMenuTrigger>
<ContextMenuContent className="min-w-[240px]">
{!disabled ? (
<>
<div className="mb-1 flex items-center gap-1 overflow-x-auto px-1 py-1">
{QUICK_REACTIONS.map((emoji) => (
<button
key={emoji}
type="button"
className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-lg transition hover:bg-[#eef1f6]"
onClick={() => onToggleReaction?.(emoji)}
>
{emoji}
</button>
))}
</div>
<ContextMenuSeparator />
</>
) : null}
{onReply && !disabled ? (
<ContextMenuItem onClick={onReply}>
<Reply className="h-4 w-4" />
Ответить
</ContextMenuItem>
) : null}
{editable ? (
<ContextMenuItem onClick={onEdit}>
<Pencil className="h-4 w-4" />
Изменить
</ContextMenuItem>
) : null}
{copyText ? (
<ContextMenuItem
onClick={() => {
void navigator.clipboard.writeText(copyText);
onCopy?.();
}}
>
<Copy className="h-4 w-4" />
Копировать текст
</ContextMenuItem>
) : null}
{onForward && !disabled && !message.isEncrypted ? (
<ContextMenuItem onClick={onForward}>
<Forward className="h-4 w-4" />
Переслать
</ContextMenuItem>
) : null}
{deletable ? (
<ContextMenuItem className="text-red-600 data-[highlighted]:bg-red-50 data-[highlighted]:text-red-700" onClick={onDelete}>
<Trash2 className="h-4 w-4" />
Удалить
</ContextMenuItem>
) : null}
{onSelect && !disabled ? (
<>
<ContextMenuSeparator />
<ContextMenuItem onClick={onSelect}>
<CheckCircle2 className="h-4 w-4" />
Выделить
</ContextMenuItem>
</>
) : null}
{!disabled && message.reactions?.length ? (
<div className="px-2 pb-1 pt-2">
<ChatMessageReactions reactions={message.reactions} onToggle={onToggleReaction} compact />
</div>
) : null}
</ContextMenuContent>
</ContextMenu>
);
}
interface SelectableMessageWrapperProps {
selected?: boolean;
selectionMode?: boolean;
align?: 'left' | 'right';
onClick?: () => void;
className?: string;
children: React.ReactNode;
}
export function SelectableMessageWrapper({
selected,
selectionMode,
align = 'left',
onClick,
className,
children
}: SelectableMessageWrapperProps) {
return (
<div
className={cn(
'relative w-fit max-w-[78%] shrink-0',
selectionMode && 'cursor-pointer',
selectionMode && (align === 'right' ? 'mr-7' : 'ml-7'),
className
)}
onClick={selectionMode ? onClick : undefined}
>
{selectionMode ? (
<span
className={cn(
'absolute top-1/2 z-10 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded-full border text-[10px] shadow-sm transition',
align === 'right' ? 'right-0 translate-x-[calc(100%+8px)]' : 'left-0 -translate-x-[calc(100%+8px)]',
selected ? 'border-[#3390ec] bg-[#3390ec] text-white' : 'border-[#dce3ec] bg-white text-transparent'
)}
>
</span>
) : null}
<div
className={cn(
'rounded-[18px] transition',
selected && 'ring-2 ring-[#3390ec] ring-offset-2 ring-offset-[#eef1f6]'
)}
>
{children}
</div>
</div>
);
}