52 lines
1.5 KiB
React
52 lines
1.5 KiB
React
import React from "react";
|
|
|
|
const palette = [
|
|
["#5B7CFA", "#2E3A66"], ["#3FB984", "#1E4536"], ["#E0A83D", "#4A3818"],
|
|
["#E5484D", "#4A1F21"], ["#B06CF0", "#38235A"], ["#48B0C8", "#193E47"],
|
|
];
|
|
|
|
function hashIndex(str) {
|
|
let h = 0;
|
|
for (let i = 0; i < str.length; i++) h = (h * 31 + str.charCodeAt(i)) >>> 0;
|
|
return h % palette.length;
|
|
}
|
|
|
|
/**
|
|
* Channel logo tile. Renders an image when given, else a generated
|
|
* initials chip keyed to the channel name — mirrors ErsatzTV's logo/gen.
|
|
*/
|
|
export function ChannelLogo({ name = "", src = null, size = 40, radius = "var(--radius-sm)", style = {} }) {
|
|
const [fg, bg] = palette[hashIndex(name)];
|
|
const initials = name
|
|
.split(/[\s\-|:]+/)
|
|
.filter(Boolean)
|
|
.slice(0, 2)
|
|
.map((w) => w[0])
|
|
.join("")
|
|
.toUpperCase() || "?";
|
|
|
|
return (
|
|
<span
|
|
style={{
|
|
display: "inline-flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
width: size,
|
|
height: size,
|
|
flex: "0 0 auto",
|
|
overflow: "hidden",
|
|
borderRadius: radius,
|
|
background: src ? "var(--ctv-bg-sunken)" : bg,
|
|
border: "1px solid var(--border-hairline)",
|
|
...style,
|
|
}}
|
|
>
|
|
{src ? (
|
|
<img src={src} alt={name} style={{ maxWidth: "100%", maxHeight: "100%", objectFit: "contain" }} />
|
|
) : (
|
|
<span style={{ font: `var(--weight-semibold) ${Math.round(size * 0.34)}px/1 var(--font-mono)`, color: fg, letterSpacing: "0.02em" }}>{initials}</span>
|
|
)}
|
|
</span>
|
|
);
|
|
}
|