parent
9cf9e07bd9
commit
14abf81de5
@ -0,0 +1,231 @@ |
||||
.round-logo img { |
||||
width: 50px; |
||||
height: auto; |
||||
display: block; |
||||
margin: 0 auto; |
||||
position: relative; |
||||
top: -100px; /* Increased negative value to move it higher up */ |
||||
} |
||||
|
||||
.round-logo img { |
||||
width: 100px; /* Adjust size as needed */ |
||||
height: auto; |
||||
display: block; |
||||
margin: 0 auto; |
||||
} |
||||
.butterfly-match.same-level::before { |
||||
display: none; |
||||
} |
||||
|
||||
/* Adjust styling for matches with single parent */ |
||||
.match-content.disabled { |
||||
visibility: hidden; |
||||
} |
||||
|
||||
.incoming-line.disabled, |
||||
.butterfly-match:has(.match-content.disabled)::after, |
||||
.butterfly-match:has(.match-content.disabled)::before { |
||||
visibility: hidden; |
||||
} |
||||
|
||||
.butterfly-bracket { |
||||
display: flex; |
||||
gap: 40px; /* Increased to account for horizontal lines (20px on each side) */ |
||||
position: relative; |
||||
margin-bottom: 80px; |
||||
} |
||||
|
||||
.round-title { |
||||
position: absolute; |
||||
top: 0px; /* Adjust this value to position the title where you want it */ |
||||
left: 50%; /* Center horizontally */ |
||||
transform: translateX(-50%); /* Center it exactly */ |
||||
text-align: center; |
||||
font-weight: bold; |
||||
width: auto; /* Change from 100% to auto */ |
||||
padding: 5px 10px; |
||||
|
||||
white-space: nowrap; /* Prevent text from wrapping */ |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: center; |
||||
} |
||||
|
||||
.round-name { |
||||
color: #707070; |
||||
font-size: 1.5em; |
||||
padding: 8px 12px; |
||||
white-space: nowrap; /* Prevent text wrapping */ |
||||
display: block; /* Ensure proper centering */ |
||||
} |
||||
|
||||
.round-format { |
||||
font-size: 0.9em; |
||||
color: #707070; |
||||
margin-top: -5px; /* Reduced from -10px to bring it closer */ |
||||
white-space: nowrap; /* Prevent text wrapping */ |
||||
display: block; /* Ensure proper centering */ |
||||
} |
||||
|
||||
.round-name.button { |
||||
border-radius: 16px; |
||||
width: 100%; |
||||
display: inline-block; |
||||
background-color: #fae7ce; |
||||
} |
||||
|
||||
.button:hover { |
||||
color: white; |
||||
background-color: #f39200; |
||||
} |
||||
|
||||
.matches-container { |
||||
position: relative; |
||||
width: 100%; |
||||
flex-grow: 1; |
||||
} |
||||
|
||||
.butterfly-round { |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
gap: 20px; /* Space between title and matches */ |
||||
position: relative; |
||||
width: var(--match-width); |
||||
flex-shrink: 0; |
||||
margin-top: 100px; /* Add padding to account for absolute positioned title */ |
||||
} |
||||
|
||||
.butterfly-match { |
||||
position: absolute; |
||||
width: 100%; |
||||
padding: 10px 10px; |
||||
} |
||||
|
||||
/* Horizontal line after match */ |
||||
.butterfly-match::after { |
||||
content: ""; |
||||
position: absolute; |
||||
left: 100%; /* Start from end of match cell */ |
||||
top: 50%; |
||||
width: 20px; |
||||
height: 2px; |
||||
background: #707070; |
||||
} |
||||
|
||||
.semi-final::after { |
||||
content: ""; |
||||
position: absolute; |
||||
left: calc(100% + 20px); /* After horizontal line */ |
||||
width: 2px; |
||||
height: calc((var(--next-match-distance)) / 2); |
||||
background: #707070; |
||||
} |
||||
|
||||
/* Vertical line connecting pair of matches */ |
||||
.butterfly-match:nth-child(2n)::before { |
||||
content: ""; |
||||
position: absolute; |
||||
left: calc(100% + 20px); /* After horizontal line */ |
||||
top: 50%; |
||||
width: 2px; |
||||
height: calc((var(--next-match-distance)) / 2); |
||||
background: #707070; |
||||
} |
||||
|
||||
.butterfly-match:nth-child(2n + 1)::before { |
||||
content: ""; |
||||
position: absolute; |
||||
left: calc(100% + 20px); |
||||
bottom: calc(50% - 2px); /* Account for half of horizontal line height */ |
||||
width: 2px; |
||||
height: calc( |
||||
((var(--next-match-distance)) / 2) |
||||
); /* Add half of horizontal line height */ |
||||
background: #707070; |
||||
} |
||||
|
||||
/* Vertical line connecting pair of matches */ |
||||
.butterfly-match.reverse-bracket:nth-child(2n)::before { |
||||
content: ""; |
||||
position: absolute; |
||||
left: calc(0% - 20px); /* After horizontal line */ |
||||
top: 50%; |
||||
width: 2px; |
||||
height: calc((var(--next-match-distance)) / 2); |
||||
background: #707070; |
||||
} |
||||
|
||||
.butterfly-match.reverse-bracket:nth-child(2n + 1)::before { |
||||
content: ""; |
||||
position: absolute; |
||||
left: calc(0% - 20px); |
||||
bottom: 50%; /* Account for half of horizontal line height */ |
||||
width: 2px; |
||||
height: calc( |
||||
(var(--next-match-distance)) / 2 |
||||
); /* Add half of horizontal line height */ |
||||
background: #707070; |
||||
} |
||||
|
||||
/* Horizontal line to next round match */ |
||||
.butterfly-match .incoming-line { |
||||
position: absolute; |
||||
left: -20px; |
||||
top: 50%; |
||||
width: 20px; |
||||
height: 2px; |
||||
background: #707070; |
||||
} |
||||
|
||||
.inward .incoming-line { |
||||
display: none; |
||||
} |
||||
|
||||
.butterfly-match.outward::after { |
||||
display: none; |
||||
} |
||||
|
||||
.butterfly-round:last-child .butterfly-match::after, |
||||
.butterfly-round:first-child .incoming-line { |
||||
display: none; |
||||
} |
||||
|
||||
.broadcast-mode .round-name, |
||||
.broadcast-mode .round-format { |
||||
padding: 0px; |
||||
color: #707070; |
||||
} |
||||
|
||||
.broadcast-mode .round-title { |
||||
padding: 8px 20px; /* Slightly more horizontal padding */ |
||||
background-color: white; |
||||
align-content: center; |
||||
border-radius: 24px; |
||||
} |
||||
/* Broadcast mode styling for all lines */ |
||||
.broadcast-mode .butterfly-match::after, |
||||
.broadcast-mode .butterfly-match:nth-child(2n)::before, |
||||
.broadcast-mode .butterfly-match:nth-child(2n + 1)::before, |
||||
.broadcast-mode .butterfly-match.reverse-bracket:nth-child(2n)::before, |
||||
.broadcast-mode .butterfly-match.reverse-bracket:nth-child(2n + 1)::before, |
||||
.broadcast-mode .butterfly-match .incoming-line, |
||||
.broadcast-mode .semi-final::after { |
||||
background-color: black; /* Bright yellow - change to your preferred color */ |
||||
} |
||||
|
||||
.bubble.match-running { |
||||
position: relative; |
||||
} |
||||
|
||||
.bubble.match-running::after { |
||||
content: ""; |
||||
position: absolute; |
||||
bottom: 0; |
||||
left: 0; |
||||
right: 0; |
||||
height: 20px; /* Height of the green indicator */ |
||||
background-color: #90ee90; /* Light green color */ |
||||
border-radius: 0 0 24px 24px; /* Match the bubble's bottom corners */ |
||||
} |
||||
@ -0,0 +1,333 @@ |
||||
function renderBracket(options) { |
||||
const bracket = document.getElementById("bracket"); |
||||
const matchTemplates = document.getElementById("match-templates").children; |
||||
const rounds = []; |
||||
const matchPositions = []; |
||||
const matchDisabled = []; |
||||
const doubleButterflyMode = options.doubleButterflyMode; |
||||
const displayLoserFinal = options.displayLoserFinal; |
||||
const tournamentId = options.tournamentId; |
||||
const isBroadcast = options.isBroadcast; |
||||
// Group matches by round
|
||||
Array.from(matchTemplates).forEach((template) => { |
||||
const roundIndex = parseInt(template.dataset.matchRound); |
||||
if (!rounds[roundIndex]) { |
||||
rounds[roundIndex] = []; |
||||
} |
||||
rounds[roundIndex].push(template); |
||||
}); |
||||
|
||||
// First create a test match to get natural height
|
||||
const firstMatch = document.createElement("div"); |
||||
firstMatch.className = "butterfly-match"; |
||||
firstMatch.innerHTML = `<div class="match-content">${rounds[0][0].innerHTML}</div>`; |
||||
bracket.appendChild(firstMatch); |
||||
const matchHeight = firstMatch.offsetHeight; |
||||
const matchSpacing = 10; |
||||
const baseDistance = matchHeight + matchSpacing; |
||||
bracket.innerHTML = ""; |
||||
const roundCount = rounds.length; |
||||
let finalRoundIndex = roundCount - 1; |
||||
if (doubleButterflyMode == true) { |
||||
finalRoundIndex = finalRoundIndex / 2; |
||||
} |
||||
let nextMatchDistance = baseDistance; |
||||
let minimumMatchDistance = 1; |
||||
|
||||
const totalRounds = document.querySelectorAll(".butterfly-round").length; |
||||
const screenWidth = window.innerWidth; |
||||
let roundTotalCount = roundCount; |
||||
if (doubleButterflyMode == true && roundCount > 1) { |
||||
roundTotalCount = roundCount - 1; |
||||
} |
||||
const padding = 50 * roundTotalCount; // Account for some padding/margin
|
||||
const availableWidth = screenWidth - padding; |
||||
let responsiveMatchWidth = Math.min( |
||||
365, |
||||
Math.floor(availableWidth / roundTotalCount), |
||||
); |
||||
|
||||
rounds.forEach((roundMatches, roundIndex) => { |
||||
if (rounds[0].length <= 2) { |
||||
minimumMatchDistance = 2; |
||||
nextMatchDistance = baseDistance * 2; |
||||
} |
||||
const roundDiv = document.createElement("div"); |
||||
roundDiv.className = "butterfly-round"; |
||||
roundDiv.style.setProperty("--match-width", `${responsiveMatchWidth}px`); |
||||
|
||||
// Create title
|
||||
const titleDiv = document.createElement("div"); |
||||
titleDiv.className = "round-title"; |
||||
|
||||
// Get the match group name and format
|
||||
const firstMatchTemplate = roundMatches[0].closest(".match-template"); |
||||
const matchGroupName = firstMatchTemplate.dataset.matchGroupName; |
||||
const matchFormat = firstMatchTemplate.dataset.matchFormat; |
||||
const roundId = firstMatchTemplate.dataset.roundId; // Add this line
|
||||
|
||||
let nameSpan = document.createElement("div"); |
||||
nameSpan.className = "round-name"; |
||||
nameSpan.textContent = matchGroupName; |
||||
if ( |
||||
roundIndex == finalRoundIndex || |
||||
(roundIndex == finalRoundIndex - 1 && displayLoserFinal) || |
||||
(roundIndex == finalRoundIndex + 1 && displayLoserFinal) || |
||||
isBroadcast |
||||
) { |
||||
} else { |
||||
nameSpan = document.createElement("a"); |
||||
nameSpan.className = "round-name"; |
||||
nameSpan.classList.add("button"); |
||||
nameSpan.textContent = matchGroupName; |
||||
if (roundId) { |
||||
nameSpan.href = `/tournament/${tournamentId}/round/${roundId}/bracket/`; |
||||
nameSpan.style.cursor = "pointer"; |
||||
} |
||||
} |
||||
|
||||
const formatSpan = document.createElement("div"); |
||||
formatSpan.className = "round-format"; |
||||
formatSpan.textContent = matchFormat; |
||||
|
||||
titleDiv.appendChild(nameSpan); |
||||
titleDiv.appendChild(formatSpan); |
||||
|
||||
// Create matches container
|
||||
const matchesContainer = document.createElement("div"); |
||||
matchesContainer.className = "matches-container"; |
||||
if (roundCount > 5 && doubleButterflyMode == true) { |
||||
if (roundIndex >= finalRoundIndex - 1) { |
||||
matchesContainer.style.transform = `translateX(-50%)`; |
||||
if (roundIndex >= finalRoundIndex + 2) { |
||||
matchesContainer.style.transform = `translateX(-100%)`; |
||||
} |
||||
} |
||||
} |
||||
roundDiv.appendChild(matchesContainer); |
||||
|
||||
matchPositions[roundIndex] = []; |
||||
matchDisabled[roundIndex] = []; // Initialize array for this round
|
||||
roundMatches.forEach((matchTemplate, matchIndex) => { |
||||
const matchTitle = matchTemplate.dataset.matchTitle; |
||||
const matchDiv = document.createElement("div"); |
||||
matchDiv.className = "butterfly-match"; |
||||
|
||||
matchDiv.style.position = "absolute"; |
||||
const isDisabled = matchTemplate.dataset.disabled === "true"; |
||||
matchDisabled[roundIndex][matchIndex] = isDisabled; |
||||
let isIncomingLineIsDisabled = isDisabled; |
||||
|
||||
let top; |
||||
let left; |
||||
let right; |
||||
const currentMatchesCount = roundMatches.length; |
||||
if (roundIndex > finalRoundIndex) { |
||||
matchDiv.classList.add("reverse-bracket"); |
||||
top = matchPositions[roundCount - roundIndex - 1][matchIndex]; |
||||
} |
||||
|
||||
if (roundIndex === 0) { |
||||
if (roundCount > 1) { |
||||
const nextMatchesCount = rounds[roundIndex + 1].length; |
||||
|
||||
if (currentMatchesCount == nextMatchesCount && roundCount > 2) { |
||||
nextMatchDistance = 0; |
||||
} |
||||
} else { |
||||
nextMatchDistance = 0; |
||||
} |
||||
|
||||
top = matchIndex * (matchHeight + matchSpacing) * minimumMatchDistance; |
||||
|
||||
if (roundCount == 3 && doubleButterflyMode) { |
||||
top = top + (matchHeight + matchSpacing) / 2; |
||||
} |
||||
} else if (roundIndex === roundCount - 1 && doubleButterflyMode == true) { |
||||
const nextMatchesCount = rounds[roundIndex - 1].length; |
||||
if (currentMatchesCount == nextMatchesCount) { |
||||
nextMatchDistance = 0; |
||||
} |
||||
} else if (roundIndex == finalRoundIndex) { |
||||
if (doubleButterflyMode == true) { |
||||
let lgth = matchPositions[0].length / 2; |
||||
let index = lgth + matchIndex - 1; |
||||
// If index goes negative, use 0 instead
|
||||
if (displayLoserFinal == true) { |
||||
if (matchIndex == 0) { |
||||
top = matchPositions[roundIndex - 1][0] - baseDistance / 2; |
||||
} else { |
||||
top = matchPositions[roundIndex - 1][0] + baseDistance / 2; |
||||
} |
||||
nextMatchDistance = baseDistance; |
||||
} else { |
||||
top = matchPositions[roundIndex - 1][0]; |
||||
nextMatchDistance = 0; |
||||
} |
||||
} else { |
||||
const parentIndex1 = matchIndex * 2; |
||||
const parentIndex2 = parentIndex1 + 1; |
||||
const parentPos1 = matchPositions[roundIndex - 1][parentIndex1]; |
||||
const parentPos2 = matchPositions[roundIndex - 1][parentIndex2]; |
||||
top = (parentPos1 + parentPos2) / 2; |
||||
nextMatchDistance = 0; |
||||
|
||||
if (displayLoserFinal == true) { |
||||
if (matchIndex == 1) { |
||||
top = matchPositions[roundIndex][0] + baseDistance + 80; |
||||
isIncomingLineIsDisabled = true; |
||||
} |
||||
} |
||||
} |
||||
} else if (roundIndex < finalRoundIndex) { |
||||
const previousMatchesCount = rounds[roundIndex - 1].length; |
||||
const nextMatchesCount = rounds[roundIndex + 1].length; |
||||
|
||||
if ( |
||||
currentMatchesCount == nextMatchesCount && |
||||
displayLoserFinal == false |
||||
) { |
||||
nextMatchDistance = 0; |
||||
} else if (matchPositions.length > roundIndex - 1) { |
||||
nextMatchDistance = |
||||
matchPositions[roundIndex - 1][1] - |
||||
matchPositions[roundIndex - 1][0]; |
||||
nextMatchDistance = |
||||
nextMatchDistance * (previousMatchesCount / currentMatchesCount); |
||||
} |
||||
|
||||
if (currentMatchesCount == previousMatchesCount) { |
||||
if (matchDisabled[roundIndex - 1][matchIndex] == true) { |
||||
isIncomingLineIsDisabled = true; |
||||
} |
||||
top = matchPositions[roundIndex - 1][matchIndex]; |
||||
} else { |
||||
const parentIndex1 = matchIndex * 2; |
||||
const parentIndex2 = parentIndex1 + 1; |
||||
const parentPos1 = matchPositions[roundIndex - 1][parentIndex1]; |
||||
const parentPos2 = matchPositions[roundIndex - 1][parentIndex2]; |
||||
top = (parentPos1 + parentPos2) / 2; |
||||
} |
||||
} else if (roundIndex < roundCount) { |
||||
const nextMatchesCount = rounds[roundIndex - 1].length; |
||||
const previousMatchesCount = rounds[roundIndex + 1].length; |
||||
|
||||
if (currentMatchesCount == nextMatchesCount) { |
||||
nextMatchDistance = 0; |
||||
} else if (matchPositions.length > roundCount - roundIndex - 1 - 1) { |
||||
nextMatchDistance = |
||||
matchPositions[roundCount - roundIndex - 1 - 1][1] - |
||||
matchPositions[roundCount - roundIndex - 1 - 1][0]; |
||||
nextMatchDistance = |
||||
nextMatchDistance * (previousMatchesCount / currentMatchesCount); |
||||
} |
||||
} |
||||
|
||||
if (roundCount > 5 && doubleButterflyMode == true) { |
||||
if (roundIndex >= finalRoundIndex - 2) { |
||||
if (roundIndex == finalRoundIndex - 1) { |
||||
matchDiv.classList.add("inward"); |
||||
} |
||||
if (roundIndex == finalRoundIndex + 1) { |
||||
matchDiv.classList.add("outward"); |
||||
} |
||||
if ( |
||||
roundIndex === finalRoundIndex - 2 || |
||||
roundIndex === finalRoundIndex + 2 |
||||
) { |
||||
nextMatchDistance = nextMatchDistance - baseDistance; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (displayLoserFinal == true) { |
||||
if ( |
||||
doubleButterflyMode == true && |
||||
(roundIndex == finalRoundIndex - 1 || |
||||
roundIndex == finalRoundIndex + 1) |
||||
) { |
||||
nextMatchDistance = baseDistance; |
||||
} |
||||
} |
||||
|
||||
matchDiv.style.setProperty( |
||||
"--next-match-distance", |
||||
`${nextMatchDistance}px`, |
||||
); |
||||
matchDiv.style.top = `${top}px`; |
||||
matchPositions[roundIndex][matchIndex] = top; |
||||
if (matchIndex === 0) { |
||||
// // Add logo for final round
|
||||
// if (roundIndex == finalRoundIndex) {
|
||||
// const logoDiv = document.createElement('div');
|
||||
// logoDiv.className = 'round-logo';
|
||||
// const logoImg = document.createElement('img');
|
||||
// logoImg.src = '/static/tournaments/images/PadelClub_logo_512.png';
|
||||
// logoImg.alt = 'PadelClub Logo';
|
||||
// logoDiv.appendChild(logoImg);
|
||||
// logoDiv.style.transform = `translateX(-50%)`;
|
||||
// matchesContainer.appendChild(logoDiv);
|
||||
// }
|
||||
|
||||
// Position title above the first match
|
||||
titleDiv.style.top = `${top - 80}px`; // Adjust the 60px offset as needed
|
||||
titleDiv.style.position = "absolute"; |
||||
if (roundCount >= 5 && doubleButterflyMode == true) { |
||||
if (roundIndex == finalRoundIndex - 1) { |
||||
titleDiv.style.marginLeft = "60px"; |
||||
} else if (roundIndex == finalRoundIndex + 1) { |
||||
titleDiv.style.marginLeft = "-60px"; |
||||
} |
||||
} |
||||
matchesContainer.appendChild(titleDiv); |
||||
} |
||||
|
||||
if ( |
||||
roundIndex == finalRoundIndex && |
||||
matchIndex === 1 && |
||||
displayLoserFinal == true && |
||||
doubleButterflyMode == false |
||||
) { |
||||
let nameSpan = document.createElement("div"); |
||||
nameSpan.className = "round-name"; |
||||
nameSpan.textContent = matchTitle; |
||||
const formatSpan = document.createElement("div"); |
||||
formatSpan.className = "round-format"; |
||||
formatSpan.textContent = matchFormat; |
||||
const titleDiv = document.createElement("div"); |
||||
titleDiv.className = "round-title"; |
||||
titleDiv.appendChild(nameSpan); |
||||
titleDiv.appendChild(formatSpan); |
||||
titleDiv.style.top = `${top - 80}px`; // Adjust the 60px offset as needed
|
||||
titleDiv.style.position = "absolute"; |
||||
matchesContainer.appendChild(titleDiv); |
||||
} |
||||
|
||||
matchDiv.innerHTML = ` |
||||
<div class="incoming-line ${isIncomingLineIsDisabled ? "disabled" : ""}"></div> |
||||
<div class="match-content ${isDisabled ? "disabled" : ""}">${matchTemplate.innerHTML}</div> |
||||
`;
|
||||
|
||||
if ( |
||||
roundIndex == finalRoundIndex - 1 && |
||||
displayLoserFinal == true && |
||||
doubleButterflyMode == true |
||||
) { |
||||
const matchDiv2 = document.createElement("div"); |
||||
matchDiv2.className = "butterfly-match"; |
||||
matchDiv2.classList.add("inward"); |
||||
matchDiv2.classList.add("semi-final"); |
||||
matchDiv2.style.setProperty( |
||||
"--next-match-distance", |
||||
`${baseDistance}px`, |
||||
); |
||||
matchDiv2.style.top = `${top}px`; |
||||
matchDiv2.innerHTML = `<div class="match-content">${rounds[0][0].innerHTML}</div>`; |
||||
matchesContainer.appendChild(matchDiv2); // Append to matchesContainer instead of roundDiv
|
||||
} |
||||
matchesContainer.appendChild(matchDiv); // Append to matchesContainer instead of roundDiv
|
||||
}); |
||||
|
||||
bracket.appendChild(roundDiv); |
||||
}); |
||||
} |
||||
@ -0,0 +1,160 @@ |
||||
<!DOCTYPE html> |
||||
{% load static %} |
||||
{% load qr_code %} |
||||
<html> |
||||
<head> |
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8" /> |
||||
<link rel="stylesheet" href="{% static 'tournaments/css/foundation.min.css' %}" /> |
||||
<link rel="stylesheet" href="{% static 'tournaments/css/basics.css' %}" /> |
||||
<link rel="stylesheet" href="{% static 'tournaments/css/style.css' %}" /> |
||||
<link rel="stylesheet" href="{% static 'tournaments/css/broadcast.css' %}" /> |
||||
<link rel="stylesheet" href="{% static 'tournaments/css/tournament_bracket.css' %}" /> |
||||
|
||||
<link rel="icon" type="image/png" href="{% static 'tournaments/images/favicon.png' %}" /> |
||||
|
||||
<title>Tableau</title> |
||||
|
||||
<script src="{% static 'tournaments/js/alpine.min.js' %}"></script> |
||||
<!-- Matomo --> |
||||
<script> |
||||
var _paq = window._paq = window._paq || []; |
||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */ |
||||
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]); |
||||
_paq.push(["setDoNotTrack", true]); |
||||
_paq.push(['trackPageView']); |
||||
_paq.push(['enableLinkTracking']); |
||||
(function() { |
||||
var u="//matomo.padelclub.app/"; |
||||
_paq.push(['setTrackerUrl', u+'matomo.php']); |
||||
_paq.push(['setSiteId', '1']); |
||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; |
||||
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); |
||||
})(); |
||||
</script> |
||||
<!-- End Matomo Code --> |
||||
</head> |
||||
|
||||
<body> |
||||
<header> |
||||
<div id="header"> |
||||
<div class="left-content bubble"> |
||||
<img src="{% static 'tournaments/images/PadelClub_logo_512.png' %}" alt="logo" class="logo"> |
||||
<div class="left-margin"> |
||||
<h1 class="club">{{ tournament.broadcast_event_display_name }}</h1> |
||||
<h1 class="event">Tableau {{ tournament.broadcast_display_name }}</h1> |
||||
</div> |
||||
</div> |
||||
<div class="right-content">{% qr_from_text qr_code_url options=qr_code_options %}</div> |
||||
</div> |
||||
</header> |
||||
|
||||
<div class="wrapper"> |
||||
<main> |
||||
<div class="bracket-container"> |
||||
<div class="butterfly-bracket" id="bracket"></div> |
||||
</div> |
||||
</main> |
||||
</div> |
||||
|
||||
<script src="{% static 'tournaments/js/tournament_bracket.js' %}"></script> |
||||
<script> |
||||
// Simple vanilla JS to handle the bracket rendering |
||||
const tournamentId = "{{ tournament.id }}"; |
||||
|
||||
function createMatchHTML(match) { |
||||
let html = '<div>'; |
||||
|
||||
// Generate HTML for each team |
||||
match.teams.forEach((team, teamIndex) => { |
||||
html += ` |
||||
<div class="match-result ${teamIndex === 0 ? 'bottom-border' : ''}"> |
||||
<div class="player ${team.names.length === 1 ? 'single-player' : 'two-players'}"> |
||||
${team.is_lucky_loser ? '<div class="overlay-text">(LL)</div>' : ''} |
||||
${team.walk_out === 1 ? '<div class="overlay-text">(WO)</div>' : ''} |
||||
|
||||
${team.names.map(name => ` |
||||
<div class="semibold ${team.walk_out === 1 ? 'strikethrough' : ''} ${team.is_winner ? 'winner' : ''}"> |
||||
${name && name.length > 0 ? name : ' '} |
||||
</div> |
||||
`).join('')} |
||||
</div> |
||||
|
||||
${match.has_walk_out ? ` |
||||
<span class="score ws w60px">${team.is_walk_out ? 'WO' : ''}</span> |
||||
` : ''} |
||||
|
||||
${team.scores && team.scores.length > 0 ? ` |
||||
<div class="scores"> |
||||
${team.scores.map(score => ` |
||||
<span class="score ws ${score.tiebreak ? 'w35px' : 'w30px'} ${team.is_winner ? 'winner' : ''}"> |
||||
${score.main} |
||||
${score.tiebreak ? `<sup>${score.tiebreak}</sup>` : ''} |
||||
</span> |
||||
`).join('')} |
||||
</div> |
||||
` : ''} |
||||
|
||||
${team.weight && !match.has_walk_out && (!team.scores || team.scores.length === 0) ? ` |
||||
<span class="score ws numbers">${team.weight}</span> |
||||
` : ''} |
||||
</div> |
||||
`; |
||||
}); |
||||
html += '</div>'; |
||||
return html; |
||||
} |
||||
|
||||
function fetchAndRenderBracket() { |
||||
fetch('/tournament/' + tournamentId + '/bracket/json/') |
||||
.then(res => res.json()) |
||||
.then((data) => { |
||||
// Create a hidden div to hold all our match templates |
||||
const tempContainer = document.createElement('div'); |
||||
tempContainer.style.display = 'none'; |
||||
tempContainer.id = 'match-templates'; |
||||
document.body.appendChild(tempContainer); |
||||
|
||||
// Create templates for each match with the right data attributes |
||||
data.match_groups.forEach((group, groupIndex) => { |
||||
group.matches.forEach((match, matchIndex) => { |
||||
const template = document.createElement('div'); |
||||
template.className = 'match-template'; |
||||
template.dataset.matchRound = groupIndex; |
||||
template.dataset.matchIndex = matchIndex; |
||||
template.dataset.disabled = match.disabled; |
||||
template.dataset.matchGroupName = group.name; |
||||
template.dataset.matchFormat = match.format; |
||||
template.dataset.matchTitle = match.title; |
||||
template.dataset.roundId = group.round_id; |
||||
|
||||
// Create the match content using our HTML generator |
||||
template.innerHTML = `<div class="bubble broadcast-bracket-match ${(!match.ended && match.started) ? 'match-running' : ''}">${createMatchHTML(match)}</div>`; |
||||
|
||||
tempContainer.appendChild(template); |
||||
}); |
||||
}); |
||||
|
||||
// Now call the renderBracket function with our data |
||||
renderBracket({ |
||||
doubleButterflyMode: true, |
||||
displayLoserFinal: true, |
||||
tournamentId: tournamentId, |
||||
isBroadcast: true |
||||
}); |
||||
|
||||
// Clean up our temporary container |
||||
document.body.removeChild(tempContainer); |
||||
|
||||
document.getElementById('bracket').classList.add('broadcast-mode'); |
||||
|
||||
}); |
||||
} |
||||
|
||||
// Initial render |
||||
fetchAndRenderBracket(); |
||||
|
||||
// Set up the refresh interval |
||||
setInterval(fetchAndRenderBracket, 15000); |
||||
</script> |
||||
</body> |
||||
</html> |
||||
Loading…
Reference in new issue