117 lines
3.1 KiB
TypeScript
117 lines
3.1 KiB
TypeScript
import Image from "next/image";
|
||
import { cn } from "@/lib/utils";
|
||
import { uniLogoYolu } from "@/lib/uni-logolar";
|
||
import { turkishSlugify } from "@/lib/slug";
|
||
|
||
/**
|
||
* Üniversite logosu; dosyası olmayanlar için ad baş harflerinden monogram.
|
||
* Logolar 300×300 PNG (public/uni-logo, kaynak YÖK Atlas) — beyaz zeminli
|
||
* kapsayıcı hem şeffaf hem beyaz arka planlı logolarda tutarlı görünür.
|
||
*/
|
||
|
||
const BOYUT: Record<"xs" | "sm" | "md" | "lg", string> = {
|
||
xs: "size-7 rounded-md p-0.5",
|
||
sm: "size-9 rounded-lg p-1",
|
||
md: "size-12 rounded-xl p-1.5",
|
||
lg: "size-16 rounded-2xl p-2 sm:size-20",
|
||
};
|
||
|
||
const MONOGRAM_METIN: Record<"xs" | "sm" | "md" | "lg", string> = {
|
||
xs: "text-[10px]",
|
||
sm: "text-xs",
|
||
md: "text-sm",
|
||
lg: "text-lg sm:text-xl",
|
||
};
|
||
|
||
// "İstanbul Teknik Üniversitesi" → "İT"; tür sözcükleri baş harfe girmez
|
||
const TUR_SOZCUKLERI = new Set([
|
||
"üniversitesi",
|
||
"üniversite",
|
||
"meslek",
|
||
"yüksekokulu",
|
||
"yüksek",
|
||
"okulu",
|
||
"ve",
|
||
]);
|
||
|
||
function monogram(ad: string): string {
|
||
const harfler = ad
|
||
.split(/\s+/)
|
||
.filter((w) => w && !TUR_SOZCUKLERI.has(w.toLocaleLowerCase("tr-TR")))
|
||
.slice(0, 2)
|
||
.map((w) => w[0].toLocaleUpperCase("tr-TR"));
|
||
return harfler.join("") || ad.slice(0, 1).toLocaleUpperCase("tr-TR");
|
||
}
|
||
|
||
/**
|
||
* Ham DB adından logo yolu: "(İL)" eki atılıp slug'lanır (katalog.ts ile
|
||
* aynı anahtar). Haritalar gibi next/image kullanamayan SVG bağlamları için.
|
||
*/
|
||
export function uniLogoYoluFromAd(ad: string): string | null {
|
||
return uniLogoYolu(turkishSlugify(ad.replace(/\s*\([^)]*\)\s*$/, "").trim()));
|
||
}
|
||
|
||
// Slug'dan deterministik pastel ton — aynı üniversite her yerde aynı renk
|
||
function tonu(slug: string): number {
|
||
let h = 0;
|
||
for (let i = 0; i < slug.length; i++) h = (h * 31 + slug.charCodeAt(i)) % 360;
|
||
return h;
|
||
}
|
||
|
||
export function UniLogo({
|
||
slug,
|
||
ad,
|
||
boy = "sm",
|
||
className,
|
||
}: {
|
||
/** Verilmezse ham addan türetilir ("(İL)" eki atılıp slug'lanır) */
|
||
slug?: string;
|
||
ad: string;
|
||
boy?: "xs" | "sm" | "md" | "lg";
|
||
className?: string;
|
||
}) {
|
||
const anahtar =
|
||
slug ?? turkishSlugify(ad.replace(/\s*\([^)]*\)\s*$/, "").trim());
|
||
const yol = uniLogoYolu(anahtar);
|
||
const px = boy === "lg" ? 80 : boy === "md" ? 48 : boy === "sm" ? 36 : 28;
|
||
|
||
if (!yol) {
|
||
const h = tonu(anahtar);
|
||
return (
|
||
<span
|
||
aria-hidden="true"
|
||
className={cn(
|
||
"flex shrink-0 select-none items-center justify-center font-heading font-bold ring-1 ring-inset ring-slate-900/10",
|
||
BOYUT[boy],
|
||
MONOGRAM_METIN[boy],
|
||
className,
|
||
)}
|
||
style={{
|
||
backgroundColor: `oklch(0.95 0.03 ${h})`,
|
||
color: `oklch(0.45 0.09 ${h})`,
|
||
}}
|
||
>
|
||
{monogram(ad)}
|
||
</span>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<span
|
||
className={cn(
|
||
"flex shrink-0 items-center justify-center bg-white ring-1 ring-inset ring-slate-900/10",
|
||
BOYUT[boy],
|
||
className,
|
||
)}
|
||
>
|
||
<Image
|
||
src={yol}
|
||
alt={`${ad} logosu`}
|
||
width={px}
|
||
height={px}
|
||
className="size-full object-contain"
|
||
/>
|
||
</span>
|
||
);
|
||
}
|