06 · Developer Guide · 레시피
인물 카드 — 사진 없을 때 로고로 대체Person Card
외부 사이트에서 인물 사진을 직접 참조해 보여줄 때 사용합니다.
사진이 없는 인물에게 외부 사이트가 「no image」 더미 URL을 돌려주면 그것을 감지해 PCL 로고 이미지로 자동 대체합니다.
언제 쓰는가
- 운영 사이트(pcltv.org)에서 인물 사진 URL을 그대로 가져올 때
- 사진 없는 인물(휴무·해외사역·신규 등)의 깨진 placeholder를 깔끔하게 처리
- 일관된 카드 디자인으로 「섬기는 사람들」 페이지를 채울 때
① 노이미지 URL 패턴 감지
pcltv는 사진 없는 인물에 3가지 패턴의 placeholder URL을 반환합니다. hasNoImage() 한 함수로 모두 잡습니다.
ts
// pcltv.org가 사진 없는 인물에게 돌려주는 「no image」 URL 식별
// 3가지 패턴 — 두 가지는 기본 noimage 이미지, 한 가지는 base64로 인코딩된 noimage.jpg
const NO_IMAGE_PATTERNS = [
"dimode.common.user", // /Images/dimode.common.user.png 같은 default avatar
"bm9pbWFnZS5qcGc=", // base64("noimage.jpg")
"noimage", // 일반 패턴
];
function hasNoImage(src: string) {
return NO_IMAGE_PATTERNS.some((p) => src.includes(p));
}② PersonCard 컴포넌트
components/preview/PersonCard.tsxtsx
import Image from "next/image";
export function PersonCard({ name, title, photo, role, note }: Person) {
const useFallback = !photo || hasNoImage(photo);
const src = useFallback ? "/brand/pcl-logo-02.svg" : photo;
return (
<li className="rounded-lg border border-border bg-white">
<div className="relative aspect-[4/5] overflow-hidden rounded-t-lg bg-cream-100">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={src}
alt={`${name} ${title}`}
className={
useFallback
? "block h-full w-full object-contain p-8 opacity-60"
: "block h-full w-full object-cover object-top"
}
/>
</div>
<div className="p-4 text-center">
<p className="text-[14px] font-bold">{name}</p>
<p className="mt-1 text-[11.5px] text-text-muted">
{title}{role && ` · ${role}`}
</p>
{note && (
<p className="mt-1 text-[10.5px] text-text-subtle">{note}</p>
)}
</div>
</li>
);
}③ 데이터 타입 + 노이미지 상수
lib/preview/staff.tsts
// lib/preview/staff.ts
export type Person = {
name: string;
title: string; // 목사·전도사·시무장로·은퇴장로 등
role?: string; // 담당 (1교구·청년부 등) 또는 임직기간
photo: string; // URL 또는 NO_IMAGE
note?: string; // 휴무·소천·해외사역 등
};
export const NO_IMAGE = "/brand/pcl-logo-02.svg";
// 운영 사이트에서 가져온 이미지는 절대 URL 그대로
// 사진이 없는 인물은 NO_IMAGE