1
0
Fork 0
polaris-task-force/src/components/frontend/account/RibbonViewer.tsx

73 lines
2.3 KiB
TypeScript

"use client";
import {
RIBBON_DEVICE_INFO,
RIBBON_CONSTANTS,
RibbonDesign,
DEFAULT_RIBBON,
} from "@/components/admin/awards/RibbonDesigner";
import { useState } from "react";
import { cn } from "@/lib/utils";
export const RibbonViewer = ({ ribbonDesign, showRibbonOnly }: { ribbonDesign: RibbonDesign, showRibbonOnly?: boolean }) => {
const initial: RibbonDesign =
ribbonDesign && typeof ribbonDesign === "object" && Array.isArray((ribbonDesign as RibbonDesign).stripes)
? (ribbonDesign as RibbonDesign)
: DEFAULT_RIBBON;
const [design] = useState<RibbonDesign>(initial);
const { stripes, devices, mirrored } = design;
if (stripes.length === 0) return null;
const displayStripes = mirrored ? [...stripes, ...stripes.slice(0, -1).reverse()] : stripes;
const totalWeight = displayStripes.reduce((sum, s) => sum + s.width, 0);
const viewWidth = RIBBON_CONSTANTS.RIBBON_WIDTH;
const viewHeight = RIBBON_CONSTANTS.PREVIEW_HEIGHT;
return (
<svg
viewBox={`0 0 ${viewWidth} ${viewHeight}`}
className={cn("h-auto max-h-20", {
"w-full rounded border border-zinc-700 bg-zinc-950": !showRibbonOnly
} )}
>
<rect x={0} y={0} width={viewWidth} height={viewHeight} rx={2} fill="#18181b" />
{(() => {
let x = 0;
return displayStripes.map((stripe, i) => {
const w = (stripe.width / totalWeight) * viewWidth;
const el = <rect key={i} x={x} y={0} width={w} height={viewHeight} fill={stripe.color} />;
x += w;
return el;
});
})()}
<image href="/images/ribbon-overlay.png" className="mix-blend-multiply w-full" />
{devices.map((device) => {
const info = RIBBON_DEVICE_INFO[device.type];
const cx = (device.position / 100) * viewWidth;
const cy = (device.positionY / 100) * viewHeight;
const fontSize = Math.min(viewHeight * 0.45, 24);
return (
<text
key={device.id}
x={cx}
y={cy}
textAnchor="middle"
dominantBaseline="central"
fill="#facc15"
fontSize={fontSize}
fontFamily="serif"
style={{ pointerEvents: "none" }}
className="text-shadow-sm text-shadow-black"
>
{info.symbol}
</text>
);
})}
</svg>
);
};