This commit is contained in:
2026-06-30 09:31:33 +07:00
parent c736326162
commit bbf8336664
77 changed files with 12601 additions and 556 deletions

View File

@@ -0,0 +1,50 @@
import React, { useEffect, useState } from 'react';
function normalizeAvatarUrl(raw?: string | null): string {
const trimmed = raw?.trim() || '';
if (!trimmed) return '';
if (trimmed.startsWith('//')) return `https:${trimmed}`;
return trimmed;
}
interface StudentAvatarProps {
fullName: string;
avatar?: string | null;
isOnline?: boolean;
size?: number;
}
export const StudentAvatar: React.FC<StudentAvatarProps> = ({
fullName,
avatar,
isOnline = false,
size = 48,
}) => {
const [imgFailed, setImgFailed] = useState(false);
const avatarUrl = normalizeAvatarUrl(avatar);
const initial = fullName ? fullName.trim().charAt(0).toUpperCase() : 'S';
const showImage = !!avatarUrl && !imgFailed;
useEffect(() => {
setImgFailed(false);
}, [avatarUrl]);
return (
<div
className={`student-workspace-avatar ${isOnline ? 'online' : ''} ${showImage ? 'has-image' : ''}`}
style={{ width: size, height: size, fontSize: size * 0.38 }}
>
{showImage ? (
<img
src={avatarUrl}
alt={fullName}
className="student-avatar-img"
referrerPolicy="no-referrer"
onError={() => setImgFailed(true)}
/>
) : (
initial
)}
</div>
);
};