PlayT2/servers.html
2025-01-26 10:37:54 -05:00

377 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>T2 Server list</title>
<style>
body {
padding: 10px;
margin: 20px;
background-color: #002b2b; /* Dark green background */
font-family: 'Source Sans Pro', sans-serif;
font-weight: 300;
color: #e2e5e5;
line-height: 1.5em;
text-shadow: 4px 4px 6px #011a1a;
background-color: #002b2b;
background-image: url("images/servers/background-xlarge.jpg");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-attachment: fixed;
}
table {
text-align: center;
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
table, td {
border: 1px solid #005f5f; /* Dark teal borders */
}
th {
background-color: #005f5f; /* Solid dark teal color for table headers */
font-family: 'Source Sans Pro', sans-serif;
font-weight: 300;
color: #e2e5e5;
line-height: 1.5em;
text-shadow: 2px 2px 4px #003030;
border: 1px solid #003030; /* Dark teal borders */
}
td {
font-family: 'Source Sans Pro', sans-serif;
font-weight: 300;
color: #e2e5e5;
line-height: 1.5em;
text-shadow: 2px 2px 4px #011a1a;
}
tr:nth-child(even) {
background-color: #038e9b15;
}
tr:hover {
background-color: #21b388; /* Slightly brighter green on hover */
background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)), url("images/overlay.png");
background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)), url("images/overlay.png");
background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)), url("images/overlay.png");
background-image: linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)), url("images/overlay.png");
-moz-transition: background-color 0.35s ease-in-out;
-webkit-transition: background-color 0.35s ease-in-out;
-ms-transition: background-color 0.35s ease-in-out;
transition: background-color 0.35s ease-in-out;
}
tr.selected {
background-color: #038f9b; /* Highlight selected row with a brighter teal */
font-weight: 300;
color: #e2e5e5;
line-height: 1.5em;
text-shadow: 2px 2px 4px #011a1a;
}
.modal {
display: none;
position: relative;
z-index: 1000;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: auto; /* Allow the width to adjust based on content */
min-width: 360px; /* Ensure the width does not shrink too small */
max-width: 1000px; /* Limit the maximum width to 800px */
background-color: rgb(0, 31, 31, 0.90); /* Dark greenish background */
border: 1px solid #005f5f; /* Same border as table */
box-shadow: 6px 6px 10px rgba(0, 0, 0, 0.555);
padding: 20px;
}
.modal-header {
font-weight: bold;
margin-bottom: 10px;
font-family: 'Source Sans Pro', sans-serif;
font-weight: 300;
color: #e2e5e5;
line-height: 1.5em;
text-shadow: 2px 2px 4px #011a1a;
}
.modal-body ul {
list-style-type: none;
padding: 0;
font-family: 'Source Sans Pro', sans-serif;
font-weight: 300;
color: #e2e5e5;
line-height: 1.5em;
text-shadow: 2px 2px 4px #011a1a;
}
.modal-body li {
margin-bottom: 5px;
}
.info_players {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.modal-close {
display: block;
font-weight: bold;
text-align: right;
margin-top: 10px;
font-family: 'Source Sans Pro', sans-serif;
font-weight: 300;
line-height: 1.75em;
font-size: 1.5em;
text-shadow: 2px 2px 4px #011a1a;
}
input[type="button"],
input[type="submit"],
input[type="reset"],
button,
.modal-close button {
width: 100px; /* Fixed width */
height: 30px; /* Fixed height */
position: relative;
display: inline-block;
border-radius: 0.15em;
color: #e4e4e4 !important;
text-shadow: 2px 2px 4px #011a1a;
text-decoration: none;
padding: 0.0em 1.5em 0.0em 1.5em;
font-size: 0.7em;
background-color: #038f9b;
border: 0;
cursor: pointer;
background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)), url("images/overlay.png");
background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)), url("images/overlay.png");
background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)), url("images/overlay.png");
background-image: linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)), url("images/overlay.png");
-moz-transition: background-color 0.35s ease-in-out;
-webkit-transition: background-color 0.35s ease-in-out;
-ms-transition: background-color 0.35s ease-in-out;
transition: background-color 0.35s ease-in-out;
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
input[type="button"]:hover,
input[type="submit"]:hover,
input[type="reset"]:hover,
button:hover,
.modal-close button:hover {
color: #e4e4e4 !important;
background-color: #21b388;
text-shadow: 2px 2px 4px #011a1a;
}
input[type="button"]:active,
input[type="submit"]:active,
input[type="reset"]:active,
.modal-close button:active,
.button:active {
background-color: #21b388;
text-shadow: 2px 2px 4px #011a1a;
}
a:link {
color: #038f9b;
background-color: transparent;
text-decoration: none;
}
a:visited {
color: #22A7B3;
background-color: transparent;
text-decoration: none;
}
a:hover {
color: #2CDCB8;
background-color: transparent;
text-decoration: underline;
}
a:active {
color: #038f9b;
background-color: transparent;
text-decoration: underline;
}
#logo .image {
position: relative;
margin: 0 0 0.5em 0;
}
#logo {
margin: 1.5em 1.25em 1.25em 1.25em;
}
#logo {
position: relative;
margin: 1.75em 1.5em 1.5em 1.5em;
min-height: 48px;
cursor: default;
}
#logo h1 {
position: relative;
color: #fff;
font-weight: 600;
font-size: 1.7em;
line-height: 1em;
margin: 0em 0em 0em 2.5em;
}
#logo p {
position: relative;
display: block;
font-size: 1.5em;
color: rgba(255, 255, 255, 0.5);
line-height: 1.25em;
margin: 0em 0em 0em 2.9em;
}
#logo .image {
position: absolute;
left: 0;
top: 0;
}
.image.avatar54 {
width: 54px;
height: 54px;
}
.image.avatar54 img {
width: 54px;
height: 54px;
}
#nav ul li a span:before {
left: 100%;
margin-left: -1.25em;
line-height: 2.25em;
}
/* Media query for mobile devices */
@media (max-width: 800px) {
body {
background-attachment: scroll; /* Change to scroll for mobile */
}
.modal {
margin: 1.5em 1.75em 1.5em 1.5em;
}
}
</style>
</head>
<body>
<!-- Logo -->
<div id="logo">
<span class="image avatar54"><img src="images/avatar.svg" alt="" /></span>
<h1><a href="https://www.tribesnext.com/" style="text-decoration: none">TribesNext Server List</a></h1>
<p>Total Players: <span id="tplayers">0</span></p>
</div>
<table id="serverlist">
<thead>
<tr>
<th>Server Name</th>
<th>Players/Bots</th>
<th>Map</th>
<th>Type</th>
<th>Mod</th>
<th>IP Address</th>
</tr>
</thead>
<tbody></tbody>
</table>
<div id="serverModal" class="modal">
<div class="modal-header">Server Details</div>
<div class="modal-body">
<div class="info_desc"></div>
<div class="info_players"></div>
<div class="modal-close">
<button id="closeModal">Close</button>
</div>
</div>
</div>
<script>
async function updateServerlist() {
try {
const response = await fetch("https://www.tribesnext.com/list.json");
const data = await response.json();
const tbody = document.querySelector('#serverlist tbody');
const tplayers = document.querySelector('#tplayers');
const modal = document.getElementById('serverModal');
const infoDesc = modal.querySelector('.info_desc');
const infoPlayers = modal.querySelector('.info_players');
const closeModalButton = document.getElementById('closeModal');
let totalPlayers = 0;
let totalBots = 0;
tbody.innerHTML = '';
for (const [sid, sobj] of Object.entries(data)) {
totalPlayers += parseInt(sobj.num_players || 0, 10);
totalBots += parseInt(sobj.num_bots || 0, 10);
const row = document.createElement('tr');
row.setAttribute('sid', sid);
row.innerHTML = `
<td scope="row">${sobj.info_hostname}</td>
<td>${sobj.num_players}/${sobj.info_flags.max_players} (${sobj.num_bots})</td>
<td>${sobj.info_map}</td>
<td>${sobj.info_maptype}</td>
<td>${sobj.info_mod}</td>
<td>${sobj.s_ipa}</td>
`;
row.addEventListener('click', () => {
document.querySelectorAll('#serverlist tr').forEach(tr => tr.classList.remove('selected'));
row.classList.add('selected');
infoDesc.textContent = sobj.info_desc || 'No description available';
if (sobj.info_players instanceof Object) {
const playerGroups = Object.entries(sobj.info_players)
.filter(([key]) => key !== "name" && key !== "score")
.map(([team, players]) => {
const teamName = players.name || 'Unknown Team';
const teamScore = players.score || 0;
const playerList = Object.entries(players)
.filter(([key]) => !isNaN(key))
.map(([key, player]) => `<div>${player.name} (Score: ${player.score})</div>`)
.join('');
return `<div><strong>${teamName} (Score: ${teamScore})</strong>${playerList}</div>`;
})
.join('');
infoPlayers.innerHTML = playerGroups;
} else {
infoPlayers.textContent = 'No player information available';
}
modal.style.display = 'block';
});
tbody.appendChild(row);
}
tplayers.textContent = `${totalPlayers} (${totalBots})`;
closeModalButton.addEventListener('click', () => {
modal.style.display = 'none';
});
window.addEventListener('click', (event) => {
if (event.target === modal) {
modal.style.display = 'none';
}
});
} catch (error) {
console.error('Error fetching server list:', error);
}
}
document.addEventListener('DOMContentLoaded', () => {
updateServerlist();
});
</script>
</body>
</html>