비행기(세계여행) 칸 선택 이동, 주사위 무게감, 설정 패널·주사위 초기화, 개인정보 고지·파비콘·탭 제목을 정리하고 런타임 로그는 추적에서 제외한다. Co-authored-by: Cursor <cursoragent@cursor.com>
79 lines
2.2 KiB
TypeScript
79 lines
2.2 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useRef } from 'react';
|
|
|
|
export type ChatFeedItem = {
|
|
id: string;
|
|
at: number;
|
|
nickname: string;
|
|
message: string;
|
|
kind: 'chat' | 'donation';
|
|
payAmount?: number;
|
|
};
|
|
|
|
export default function ChatFeedPanel({
|
|
items,
|
|
visible,
|
|
compact = false,
|
|
}: {
|
|
items: ChatFeedItem[];
|
|
visible: boolean;
|
|
compact?: boolean;
|
|
}) {
|
|
const listRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
const el = listRef.current;
|
|
if (!el) return;
|
|
el.scrollTop = el.scrollHeight;
|
|
}, [items.length, items[items.length - 1]?.id]);
|
|
|
|
if (!visible) return null;
|
|
|
|
return (
|
|
<div
|
|
className={
|
|
compact
|
|
? 'flex h-full max-h-[200px] min-h-0 w-full flex-col overflow-hidden rounded-md bg-black/75 text-white shadow-md'
|
|
: 'flex h-full min-h-0 w-full flex-col overflow-hidden rounded-lg bg-black/70 text-white shadow-lg'
|
|
}
|
|
>
|
|
<div
|
|
className={
|
|
compact
|
|
? 'shrink-0 border-b border-white/10 px-1.5 py-0.5 text-[20px] font-semibold text-white/80'
|
|
: 'shrink-0 border-b border-white/10 px-2 py-1 text-[22px] font-semibold text-white/80'
|
|
}
|
|
>
|
|
채팅
|
|
</div>
|
|
<div
|
|
ref={listRef}
|
|
className={
|
|
compact
|
|
? 'min-h-0 flex-1 space-y-0.5 overflow-y-auto px-1.5 py-1 text-[20px] leading-snug'
|
|
: 'min-h-0 flex-1 space-y-1 overflow-y-auto px-2 py-1.5 text-[22px] leading-snug'
|
|
}
|
|
>
|
|
{items.length === 0 ? (
|
|
<p className="text-white/40">채팅 대기 중…</p>
|
|
) : (
|
|
items.map((item) => (
|
|
<p
|
|
key={item.id}
|
|
className={item.kind === 'donation' ? 'text-amber-200' : 'text-white/90'}
|
|
>
|
|
<span className="font-semibold text-white/70">{item.nickname}</span>
|
|
<span className="text-white/40">: </span>
|
|
<span>{item.message || (item.kind === 'donation' ? '치즈 후원' : '')}</span>
|
|
{item.kind === 'donation' && item.payAmount != null ? (
|
|
<span className="text-amber-300"> ({item.payAmount}치즈)</span>
|
|
) : null}
|
|
</p>
|
|
))
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|