General clean-up
This commit is contained in:
@@ -4,7 +4,6 @@ import { useEffect, useRef, useState } from 'react';
|
||||
import MatchCard from "./MatchCard";
|
||||
import Podium from './Podium';
|
||||
|
||||
|
||||
export default function BracketView({ matches, onMatchClick }) {
|
||||
const containerRef = useRef(null);
|
||||
const [lines, setLines] = useState([]);
|
||||
@@ -14,23 +13,58 @@ export default function BracketView({ matches, onMatchClick }) {
|
||||
if (!containerRef.current) return;
|
||||
const container = containerRef.current.getBoundingClientRect();
|
||||
const newLines = [];
|
||||
|
||||
matches.forEach(m => {
|
||||
if (!m.winner_next_match_id) return;
|
||||
const sEl = document.getElementById(`match-${m.id}`);
|
||||
const eEl = document.getElementById(`match-${m.winner_next_match_id}`);
|
||||
if (sEl && eEl) {
|
||||
const r1 = sEl.getBoundingClientRect(), r2 = eEl.getBoundingClientRect();
|
||||
const sx = r1.right - container.left, sy = r1.top + r1.height / 2 - container.top;
|
||||
const ex = r2.left - container.left, ey = r2.top + r2.height / 2 - container.top;
|
||||
const c1 = sx + (ex - sx) / 2;
|
||||
newLines.push(<path key={`${m.id}-${m.winner_next_match_id}`} d={`M ${sx} ${sy} C ${c1} ${sy}, ${c1} ${ey}, ${ex} ${ey}`} className="stroke-zinc-300 dark:stroke-zinc-700 fill-none stroke-[1.5px]" />);
|
||||
if (m.winner_next_match_id) {
|
||||
const sEl = document.getElementById(`match-${m.id}`);
|
||||
const eEl = document.getElementById(`match-${m.winner_next_match_id}`);
|
||||
if (sEl && eEl) {
|
||||
const r1 = sEl.getBoundingClientRect(), r2 = eEl.getBoundingClientRect();
|
||||
const sx = r1.right - container.left, sy = r1.top + r1.height / 2 - container.top;
|
||||
const ex = r2.left - container.left, ey = r2.top + r2.height / 2 - container.top;
|
||||
const c1 = sx + (ex - sx) / 2;
|
||||
newLines.push(
|
||||
<path key={`w-${m.id}`} d={`M ${sx} ${sy} C ${c1} ${sy}, ${c1} ${ey}, ${ex} ${ey}`} className="stroke-zinc-300 dark:stroke-zinc-700 print:!stroke-zinc-400 fill-none stroke-[1.5px]" />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (m.loser_next_match_id) {
|
||||
const targetMatch = matches.find(x => x.id === m.loser_next_match_id);
|
||||
if (targetMatch && targetMatch.bracket === 'Finals') {
|
||||
const sEl = document.getElementById(`match-${m.id}`);
|
||||
const eEl = document.getElementById(`match-${targetMatch.id}`);
|
||||
if (sEl && eEl) {
|
||||
const r1 = sEl.getBoundingClientRect(), r2 = eEl.getBoundingClientRect();
|
||||
const sx = r1.right - container.left, sy = r1.top + r1.height / 2 - container.top;
|
||||
const ex = r2.left - container.left, ey = r2.top + r2.height / 2 - container.top;
|
||||
const c1 = sx + (ex - sx) / 2;
|
||||
newLines.push(
|
||||
<path key={`l-${m.id}`} strokeDasharray="6 6" d={`M ${sx} ${sy} C ${c1} ${sy}, ${c1} ${ey}, ${ex} ${ey}`} className="stroke-zinc-300 dark:stroke-zinc-700 print:!stroke-zinc-400 fill-none stroke-[1.5px]" />
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
setLines(newLines);
|
||||
};
|
||||
|
||||
const t = setTimeout(draw, 100);
|
||||
window.addEventListener('resize', draw);
|
||||
return () => { clearTimeout(t); window.removeEventListener('resize', draw); };
|
||||
|
||||
const handlePrint = () => { draw(); setTimeout(draw, 100); };
|
||||
const mql = window.matchMedia('print');
|
||||
mql.addEventListener('change', handlePrint);
|
||||
window.addEventListener('beforeprint', handlePrint);
|
||||
window.addEventListener('afterprint', draw);
|
||||
|
||||
return () => {
|
||||
clearTimeout(t);
|
||||
window.removeEventListener('resize', draw);
|
||||
mql.removeEventListener('change', handlePrint);
|
||||
window.removeEventListener('beforeprint', handlePrint);
|
||||
window.removeEventListener('afterprint', draw);
|
||||
};
|
||||
}, [matches]);
|
||||
|
||||
const renderRound = (list) => {
|
||||
@@ -66,43 +100,64 @@ export default function BracketView({ matches, onMatchClick }) {
|
||||
});
|
||||
};
|
||||
|
||||
const isDoubleElim = matches.some(m => m.bracket === 'Loser');
|
||||
const wb = matches.filter(m => m.bracket === 'Winner');
|
||||
const lb = matches.filter(m => m.bracket === 'Loser');
|
||||
const finals = matches.filter(m => m.bracket === 'Finals');
|
||||
|
||||
let displayWb = [...wb];
|
||||
let displayFinals = [...finals];
|
||||
|
||||
if (!isDoubleElim && displayWb.length > 0) {
|
||||
const maxRound = Math.max(...displayWb.map(m => m.round));
|
||||
const gfIndex = displayWb.findIndex(m => m.round === maxRound);
|
||||
|
||||
if (gfIndex !== -1) {
|
||||
const gfMatch = displayWb.splice(gfIndex, 1)[0];
|
||||
displayFinals.unshift(gfMatch);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full h-full overflow-auto bg-[#f8f9fa] dark:bg-zinc-950 bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] dark:bg-[radial-gradient(#27272a_1px,transparent_1px)] [background-size:24px_24px]">
|
||||
<div className="w-full h-full overflow-auto print:overflow-visible print:h-auto print:w-auto bg-[#f8f9fa] dark:bg-zinc-950 bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] dark:bg-[radial-gradient(#27272a_1px,transparent_1px)] [background-size:24px_24px] print:!bg-white print:!bg-none">
|
||||
<style>
|
||||
{`@media print {
|
||||
@page { size: landscape; margin: 0.5cm; }
|
||||
body { -webkit-print-color-adjust: exact; print-color-adjust: exact; background: white !important; }
|
||||
}`}
|
||||
</style>
|
||||
|
||||
<div ref={containerRef} className="relative min-w-max min-h-full p-12 flex gap-20 items-center">
|
||||
<svg className="absolute inset-0 w-full h-full pointer-events-none z-0">
|
||||
<svg className="absolute inset-0 w-full h-full pointer-events-none z-0 print:overflow-visible">
|
||||
{lines}
|
||||
</svg>
|
||||
|
||||
<div className="flex flex-col gap-24">
|
||||
<div className="relative">
|
||||
<div className="absolute -top-8 left-0 text-[10px] font-black uppercase tracking-[0.2em] text-zinc-400">Winners Bracket</div>
|
||||
<div className="flex gap-20">{renderRound(wb)}</div>
|
||||
<div className="absolute -top-8 left-0 text-[10px] font-black uppercase tracking-[0.2em] text-zinc-400 print:!text-black">Winners Bracket</div>
|
||||
<div className="flex gap-20">{renderRound(displayWb)}</div>
|
||||
</div>
|
||||
{matches.some(m => m.bracket === 'Loser') && (
|
||||
<div className="relative pt-8 border-t border-dashed border-zinc-300 dark:border-zinc-800">
|
||||
<div className="absolute top-0 left-0 text-[10px] font-black uppercase tracking-[0.2em] text-zinc-400">Losers Bracket</div>
|
||||
<div className="flex gap-20 mt-8">{renderRound(lb)}</div>
|
||||
{isDoubleElim && (
|
||||
<div className="relative pt-8 border-t border-dashed border-zinc-300 dark:border-zinc-800 print:!border-zinc-400">
|
||||
<div className="absolute top-4 left-0 text-[10px] font-black uppercase tracking-[0.2em] text-zinc-400 print:!text-black">Losers Bracket</div>
|
||||
<div className="flex gap-20 mt-4">{renderRound(lb)}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col justify-center gap-6 z-10">
|
||||
{matches.some(m => m.bracket === 'Finals') && (
|
||||
<>
|
||||
<div className="text-[10px] font-black uppercase bg-orange-100 dark:bg-orange-900/30 text-orange-600 px-4 py-1.5 rounded-full border border-orange-200 dark:border-orange-800 shadow-sm mx-auto">Championship</div>
|
||||
{finals.map(m => <MatchCard key={m.id} match={m} onClick={onMatchClick} />)}
|
||||
</>
|
||||
{displayFinals.length > 0 && (
|
||||
<div className="relative flex flex-col gap-6">
|
||||
<div className="absolute -top-10 left-1/2 -translate-x-1/2 text-[10px] font-black uppercase bg-orange-100 dark:bg-orange-900/30 text-orange-600 print:!bg-transparent print:!border-black print:!text-black px-4 py-1.5 rounded-full border border-orange-200 dark:border-orange-800 shadow-sm whitespace-nowrap">
|
||||
Championship
|
||||
</div>
|
||||
{displayFinals.map(m => <MatchCard key={m.id} match={m} onClick={onMatchClick} />)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
<div className="flex flex-col justify-center gap-6 z-10">
|
||||
<Podium matches={matches} />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user