72 lines
2.2 KiB
TypeScript
72 lines
2.2 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState, useEffect } from 'react';
|
|
import Image, { ImageProps } from 'next/image';
|
|
|
|
interface TransparentImageProps extends Omit<ImageProps, 'src'> {
|
|
src: string;
|
|
alt: string;
|
|
teamOrBrandName?: string;
|
|
theme?: 'light' | 'dark'; // bg-stone-50 vs bg-stone-900
|
|
}
|
|
|
|
/**
|
|
* 字串過濾器 (String Formatter)
|
|
* 確保專有名詞的大小寫與字元間距嚴格對齊
|
|
*/
|
|
export const formatBrandName = (name: string) => {
|
|
return name.toUpperCase().replace(/\s+/g, ' ').trim();
|
|
};
|
|
|
|
export default function TransparentImage({
|
|
src,
|
|
alt,
|
|
teamOrBrandName,
|
|
theme = 'dark',
|
|
className = '',
|
|
...props
|
|
}: TransparentImageProps) {
|
|
|
|
const [isValidAlpha, setIsValidAlpha] = useState<boolean | null>(null);
|
|
|
|
useEffect(() => {
|
|
// 實務上這裡可以加上 Canvas 檢查,掃描圖片角落是否有典型的實體灰白棋盤格特徵
|
|
// 或者只允許載入已經過後端白名單校驗的 CDN 圖片
|
|
// 這裡我們假設 src 來自信任的 CDN 或本地 public
|
|
setIsValidAlpha(true);
|
|
}, [src]);
|
|
|
|
// 防呆機制:若檢測到無效透明度,顯示佔位符
|
|
if (isValidAlpha === false) {
|
|
return (
|
|
<div className={`flex flex-col items-center justify-center border border-quant-red border-dashed rounded ${className} p-2`}>
|
|
<span className="text-quant-red font-dotmatrix text-[10px] uppercase">Alpha Error</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// 移除 `mix-blend-mode` 偽裝去背,嚴格要求圖檔自帶真實 Alpha Channel
|
|
|
|
return (
|
|
<div className={`flex flex-col items-center ${className}`}>
|
|
<div className={`relative ${props.width ? `w-[${props.width}px]` : 'w-full'} ${props.height ? `h-[${props.height}px]` : 'h-full'}`}>
|
|
<Image
|
|
src={src}
|
|
alt={alt}
|
|
className="object-contain"
|
|
{...props}
|
|
/>
|
|
</div>
|
|
{teamOrBrandName && (
|
|
<span className="mt-2 text-sm font-dotmatrix tracking-widest uppercase">
|
|
{theme === 'dark' ? (
|
|
<span className="text-stone-300">{formatBrandName(teamOrBrandName)}</span>
|
|
) : (
|
|
<span className="text-stone-800">{formatBrandName(teamOrBrandName)}</span>
|
|
)}
|
|
</span>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|