67 lines
1.6 KiB
TypeScript
67 lines
1.6 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState } from 'react';
|
|
import styled from 'styled-components';
|
|
import { API_URL } from '@/lib/config';
|
|
|
|
const SISTER_INITIALS: Record<string, string> = {
|
|
harang: '하',
|
|
narang: '나',
|
|
darang: '다',
|
|
erang: '이',
|
|
};
|
|
|
|
const ImgEl = styled.img<{ $size: number }>`
|
|
width: ${({ $size }) => $size}px;
|
|
height: ${({ $size }) => $size}px;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
border: 1px solid var(--border-color);
|
|
background: #111;
|
|
display: block;
|
|
flex-shrink: 0;
|
|
`;
|
|
|
|
const Fallback = styled.div<{ $size: number }>`
|
|
width: ${({ $size }) => $size}px;
|
|
height: ${({ $size }) => $size}px;
|
|
border-radius: 50%;
|
|
background: #222;
|
|
border: 1px solid var(--border-color);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-family: var(--font-mono);
|
|
font-size: ${({ $size }) => Math.round($size * 0.4)}px;
|
|
color: var(--text-secondary);
|
|
flex-shrink: 0;
|
|
user-select: none;
|
|
`;
|
|
|
|
interface SisterAvatarProps {
|
|
name: string;
|
|
size?: number;
|
|
className?: string;
|
|
style?: React.CSSProperties;
|
|
}
|
|
|
|
export default function SisterAvatar({ name, size = 32, className, style }: SisterAvatarProps) {
|
|
const [failedFor, setFailedFor] = useState<string | null>(null);
|
|
const initial = SISTER_INITIALS[name] ?? name.slice(0, 1).toUpperCase();
|
|
|
|
if (failedFor === name) {
|
|
return <Fallback $size={size} className={className} style={style}>{initial}</Fallback>;
|
|
}
|
|
|
|
return (
|
|
<ImgEl
|
|
$size={size}
|
|
src={`${API_URL}/api/sisters/${name}/avatar`}
|
|
alt={name}
|
|
className={className}
|
|
style={style}
|
|
onError={() => setFailedFor(name)}
|
|
/>
|
|
);
|
|
}
|