1
0
mirror of https://github.com/KubaPro010/fm-dx-webserver.git synced 2026-02-26 22:13:53 +01:00

backgrounds, new banlist, bugfixes, presets

This commit is contained in:
NoobishSVK
2024-03-24 18:24:19 +01:00
parent 72953a2529
commit f855cbb78a
14 changed files with 318 additions and 66 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "fm-dx-webserver",
"version": "1.1.6",
"version": "1.1.7",
"description": "",
"main": "index.js",
"scripts": {

View File

@@ -209,6 +209,7 @@ var dataToSend = {
previousFreq: 87.500.toFixed(3),
signal: 0,
highestSignal: -Infinity,
bw: 0,
st: false,
st_forced: false,
rds: false,
@@ -299,7 +300,8 @@ function handleData(ws, receivedData) {
}
break;
case receivedLine.startsWith('W'): // Bandwidth
console.log(receivedLine);
initialData.bw = receivedLine.substring(1);
dataToSend.bw = receivedLine.substring(1);
break;
case receivedLine.startsWith('Sm'):
processSignal(receivedLine, false, false);

View File

@@ -16,6 +16,11 @@ const fmdxList = require('./fmdx_list');
// Endpoints
router.get('/', (req, res) => {
if(serverConfig.webserver.banlist.includes(req.connection.remoteAddress)) {
res.render('403');
return;
}
if (configExists() === false) {
let serialPorts;
@@ -45,7 +50,7 @@ router.get('/', (req, res) => {
tunerLock: serverConfig.lockToAdmin,
publicTuner: serverConfig.publicTuner,
ownerContact: serverConfig.identification.contact,
antennaSwitch: serverConfig.antennaSwitch,
antennas: serverConfig.antennas ? serverConfig.antennas : {},
tuningLimit: serverConfig.webserver.tuningLimit,
tuningLowerLimit: serverConfig.webserver.tuningLowerLimit,
tuningUpperLimit: serverConfig.webserver.tuningUpperLimit,
@@ -204,7 +209,8 @@ router.get('/static_data', (req, res) => {
qthLatitude: serverConfig.identification.lat,
qthLongitude: serverConfig.identification.lon,
presets: serverConfig.webserver.presets || [],
defaultTheme: serverConfig.webserver.defaultTheme || 'theme1'
defaultTheme: serverConfig.webserver.defaultTheme || 'theme1',
bgImage: serverConfig.webserver.bgImage || ''
});
});

View File

@@ -72,7 +72,7 @@ function connectToSerial() {
serialport.write('x\n');
serialport.write('W0\n');
serialport.write('M0\n');
serialport.write('Y100\n');
serverConfig.audio.startupVolume ? serialport.write('Y' + (serverConfig.audio.startupVolume * 100).toFixed(0) + '\n') : serialport.write('Y100\n');
serialport.write('D0\n');
serialport.write('A0\n');
serialport.write('F-1\n');
@@ -162,7 +162,7 @@ function connectToXdrd() {
client.write('x\n');
client.write(serverConfig.defaultFreq ? 'T' + Math.round(serverConfig.defaultFreq * 1000) + '\n' : 'T87500\n');
client.write('A0\n');
client.write('G00\n');
client.write(serverConfig.audio.startupVolume ? 'Y' + (serverConfig.audio.startupVolume * 100).toFixed(0) + '\n' : 'Y100\n');
client.off('data', authDataHandler);
return;
}

View File

@@ -59,7 +59,15 @@
border: 1px solid var(--color-4);
position: relative;
z-index: 999;
max-height: 400px;
overflow-y: auto;
}
.dropdown .options.open-top {
transform: initial;
bottom: 100%;
}
.dropdown .options .option {
color: var(--color-4);
padding: 7px;

View File

@@ -45,7 +45,8 @@
body {
font-family: 'Titillium Web', sans-serif;
color: var(--color-text);
background-color: var(--color-main);
background: var(--color-main);
background-blend-mode: multiply;
transition: 0.3s ease-in-out background-color;
margin: 0 auto;
}

View File

@@ -133,23 +133,23 @@
<button class="playbutton" aria-label="Play/Stop"><i class="fa-solid fa-play"></i></button>
</div>
<% if (antennaSwitch) { %>
<div class="panel-50 no-bg h-100 m-0 dropdown" id="data-ant" style="margin-right: 25px;">
<% if (antennas.enabled == true) { %>
<div class="panel-50 no-bg h-100 m-0 dropdown" id="data-ant" style="margin-right: 25px;width:125px;">
<input type="text" placeholder="Ant A" readonly>
<ul class="options">
<li data-value="0" class="option">Ant A</li>
<li data-value="1" class="option">Ant B</li>
<li data-value="2" class="option">Ant C</li>
<li data-value="3" class="option">Ant D</li>
<% if(antennas.ant1.enabled == true) { %><li data-value="0" class="option"><%= antennas.ant1.name %></li><% } %>
<% if(antennas.ant2.enabled == true) { %><li data-value="1" class="option"><%= antennas.ant2.name %></li><% } %>
<% if(antennas.ant3.enabled == true) { %><li data-value="2" class="option"><%= antennas.ant3.name %></li><% } %>
<% if(antennas.ant4.enabled == true) { %><li data-value="3" class="option"><%= antennas.ant4.name %></li><% } %>
</ul>
</div>
<% } %>
<div class="panel-100 no-bg h-100 m-0 button-eq">
<div class="panel-50 no-bg h-100 m-0 button-eq">
<% if (device == 'tef') { %><button id="data-eq" style="border-radius: 30px 0px 0px 30px;" class="tooltip" aria-label="EQ Filter" data-tooltip="<strong>The cEQ filter can reduce bandwidth below 56 KHz.</strong><br><br>Useful for weak stations next to strong ones,<br>although it may pick up more interference."><span class="text-bold">cEQ</span></button><% } %>
<% if (device == 'xdr') { %><button id="data-eq" style="border-radius: 30px 0px 0px 30px;" class="tooltip" aria-label="RF+ Filter" data-tooltip="<strong>The RF+ filter increases gain by 5dB</strong>"><span class="text-bold">RF+</span></button><% } %>
</div>
<div class="panel-100 no-bg h-100 m-0 button-ims">
<div class="panel-50 no-bg h-100 m-0 button-ims">
<% if (device == 'tef') { %><button id="data-ims" style="border-radius: 0px 30px 30px 0px;" class="tooltip" aria-label="iMS + Filter" data-tooltip="<strong>The iMS filter reduces multipath audio artifacts.</strong><br><br>It's recommended to leave it on most of the time."><span class="text-bold">iMS</span></button><% } %>
<% if (device == 'xdr') { %><button id="data-ims" style="border-radius: 0px 30px 30px 0px;" class="tooltip" aria-label="IF+ Filter" data-tooltip="<strong>The IF+ filter increases gain by 6dB</strong>"><span class="text-bold">IF+</span></button><% } %>
</div>
@@ -162,8 +162,101 @@
<button id="freq-up" aria-label="Tune up by 100 KHz"><i class="fa-solid fa-chevron-right"></i></button>
</div>
<div class="panel-33 hide-phone" style="height: 48px;">
<input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="1" aria-label="Volume slider">
<div class="panel-33 hide-phone no-bg">
<div class="flex-container">
<% if(device === 'other') { %>
<span class="panel-100 m-0 h-100" style="height: 48px;width: 100%;">
<input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="1" aria-label="Volume slider">
</span>
<% } else { %>
<span class="panel-100 m-0" style="margin-right: 15px !important;">
<input type="range" id="volumeSlider" min="0" max="1" step="0.01" value="1" aria-label="Volume slider">
</span>
<% } %>
<% if (device == 'tef') { %>
<div class="panel-50 w-150 no-bg h-100 m-0 dropdown" id="data-bw" style="margin-left: 25px;">
<input type="text" placeholder="Auto BW" readonly>
<ul class="options open-top">
<li data-vlaue="0" class="option">Auto</li>
<li data-value="56000" class="option">56 KHz</li>
<li data-value="64000" class="option">64 KHz</li>
<li data-value="72000" class="option">72 KHz</li>
<li data-value="84000" class="option">84 KHz</li>
<li data-value="97000" class="option">97 KHz</li>
<li data-value="114000" class="option">114 KHz</li>
<li data-value="133000" class="option">133 KHz</li>
<li data-value="151000" class="option">151 KHz</li>
<li data-value="184000" class="option">184 KHz</li>
<li data-value="200000" class="option">200 KHz</li>
<li data-value="217000" class="option">217 KHz</li>
<li data-value="236000" class="option">236 KHz</li>
<li data-value="254000" class="option">254 KHz</li>
<li data-value="287000" class="option">287 KHz</li>
<li data-value="311000" class="option">311 KHz</li>
</ul>
</div>
<% } %>
<% if (device == 'xdr') { %>
<div class="panel-50 w-150 no-bg h-100 m-0 dropdown" id="data-bw" style="margin-left: 25px;">
<input type="text" placeholder="Auto BW" readonly>
<ul class="options open-top">
<li data-vlaue="0" class="option">Auto</li>
<li data-value="9000" class="option">9 KHz</li>
<li data-value="15000" class="option">15 KHz</li>
<li data-value="17000" class="option">17 KHz</li>
<li data-value="20000" class="option">20 KHz</li>
<li data-value="24000" class="option">24 KHz</li>
<li data-value="27000" class="option">27 KHz</li>
<li data-value="32000" class="option">32 KHz</li>
<li data-value="36000" class="option">36 KHz</li>
<li data-value="42000" class="option">42 KHz</li>
<li data-value="48000" class="option">48 KHz</li>
<li data-value="55000" class="option">55 KHz</li>
<li data-value="63000" class="option">63 KHz</li>
<li data-value="73000" class="option">73 KHz</li>
<li data-value="83000" class="option">83 KHz</li>
<li data-value="90000" class="option">90 KHz</li>
<li data-value="95000" class="option">95 KHz</li>
<li data-value="108000" class="option">108 KHz</li>
<li data-value="125000" class="option">125 KHz</li>
<li data-value="142000" class="option">142 KHz</li>
<li data-value="159000" class="option">159 KHz</li>
<li data-value="177000" class="option">177 KHz</li>
<li data-value="194000" class="option">194 KHz</li>
<li data-value="211000" class="option">211 KHz</li>
<li data-value="229000" class="option">229 KHz</li>
<li data-value="246000" class="option">246 KHz</li>
<li data-value="263000" class="option">263 KHz</li>
<li data-value="281000" class="option">281 KHz</li>
<li data-value="298000" class="option">298 KHz</li>
<li data-value="309000" class="option">309 KHz</li>
</ul>
</div>
<% } %>
<% if (device == 'sdr') { %>
<div class="panel-50 w-150 no-bg h-100 m-0 dropdown" id="data-bw" style="margin-left: 25px;">
<input type="text" placeholder="Auto BW" readonly>
<ul class="options open-top">
<li data-vlaue="0" class="option">Auto</li>
<li data-value="4000" class="option">4 KHz</li>
<li data-value="8000" class="option">8 KHz</li>
<li data-value="10000" class="option">10 KHz</li>
<li data-value="20000" class="option">20 KHz</li>
<li data-value="30000" class="option">30 KHz</li>
<li data-value="50000" class="option">50 KHz</li>
<li data-value="75000" class="option">75 KHz</li>
<li data-value="100000" class="option">100 KHz</li>
<li data-value="125000" class="option">125 KHz</li>
<li data-value="150000" class="option">150 KHz</li>
<li data-value="175000" class="option">175 KHz</li>
<li data-value="200000" class="option">200 KHz</li>
<li data-value="225000" class="option">225 KHz</li>
</ul>
</div>
<% } %>
</div>
</div>
</div>
@@ -181,7 +274,7 @@
<span id="data-station-name"></span>
</h2>
<h4 class="m-0">
<span id="data-station-city"></span>, <span id="data-station-itu"></span>
<span id="data-station-city" style="font-size: 16px;"></span> <span class="text-small">[<span id="data-station-itu"></span>]</span>
</h4>
<span class="text-small">
<span id="data-station-erp"></span> kW [<span id="data-station-pol"></span>] <span class="text-gray">•</span> <span id="data-station-distance"></span> km <span class="text-gray">•</span> <span id="data-station-azimuth"></span>°
@@ -316,7 +409,7 @@
<% } %>
<div id="login-message"></div>
<h2>Time:</h2>
<h2>Time</h2>
<p class="m-0">Server: <span class="color-3" id="server-time"></span></p>
<p class="m-0">Local: <span class="color-3" id="client-time"></span></p>
@@ -324,6 +417,10 @@
<div class="version-info">
<p class="text-small">FM-DX WebServer <br>by <a href="https://noobish.eu" target="_blank">Noobish</a>, <a href="https://fmdx.pl" target="_blank">kkonradpl</a> & the OpenRadio community.</p>
<% if (device == 'tef') { %><p class="m-0">Device: TEF668x</p> <% } %>
<% if (device == 'xdr') { %><p class="m-0">Device: Sony XDR</p> <% } %>
<% if (device == 'sdr') { %><p class="m-0">Device: SDR</p> <% } %>
<span style="color: var(--color-3);" class="version-string"></span><br>
<span class="text-small" style="color: var(--color-3);">[<a href="https://list.fmdx.pl" target="_blank">Receiver Map</a>]</span>
<br>

View File

@@ -9,7 +9,19 @@ function submitData() {
var themeSelectedValue = $("#selected-theme").val();
var themeDataValue = $(".option:contains('" + themeSelectedValue + "')").attr('data-value') || 'theme1';
const defaultTheme = themeDataValue;
const bgImage = $("#bg-image").val() || '';
const ant1enabled = $('#ant1-enabled').is(":checked") || false;
const ant2enabled = $('#ant2-enabled').is(":checked") || false;
const ant3enabled = $('#ant3-enabled').is(":checked") || false;
const ant4enabled = $('#ant4-enabled').is(":checked") || false;
const ant1name = $("#ant1-name").val() || 'Ant A';
const ant2name = $("#ant2-name").val() || 'Ant B';
const ant3name = $("#ant3-name").val() || 'Ant C';
const ant4name = $("#ant4-name").val() || 'Ant D';
let presets = [];
presets.push($('#preset1').val() || '87.5');
presets.push($('#preset2').val() || '87.5');
@@ -46,6 +58,7 @@ function submitData() {
}).data('value') || "tef");
const softwareMode = $('#audio-software-mode').is(":checked") || false;
const startupVolume = $('#startup-volume').val() || '100';
const tunerName = $('#webserver-name').val() || 'FM Tuner';
const tunerDesc = $('#webserver-desc').val() || 'Default FM tuner description';
@@ -61,7 +74,7 @@ function submitData() {
const publicTuner = $("#tuner-public").is(":checked");
const lockToAdmin = $("#tuner-lock").is(":checked");
const autoShutdown = $("#shutdown-tuner").is(":checked") || false;
const antennaSwitch = $("#antenna-switch").is(":checked") || false;
const antennasEnabled = $("#antenna-switch").is(":checked") || false;
const data = {
webserver: {
@@ -73,7 +86,27 @@ function submitData() {
chatEnabled,
defaultTheme,
presets,
banlist
banlist,
bgImage
},
antennas: {
enabled: antennasEnabled,
ant1: {
enabled: ant1enabled,
name: ant1name
},
ant2: {
enabled: ant2enabled,
name: ant2name
},
ant3: {
enabled: ant3enabled,
name: ant3name
},
ant4: {
enabled: ant4enabled,
name: ant4name
},
},
xdrd: {
comPort,
@@ -87,6 +120,7 @@ function submitData() {
audioChannels,
audioBitrate,
softwareMode,
startupVolume,
},
identification: {
tunerName,
@@ -105,7 +139,6 @@ function submitData() {
publicTuner,
lockToAdmin,
autoShutdown,
antennaSwitch,
enableDefaultFreq,
defaultFreq,
};
@@ -130,7 +163,6 @@ function submitData() {
}
function fetchData() {
// Make a GET request to retrieve the data.json file
fetch("./getData")
.then(response => {
if (!response.ok) {
@@ -154,6 +186,10 @@ function submitData() {
if (selectedTheme.length > 0) {
$("#selected-theme").val(selectedTheme.text());
}
if (data.webserver.bgImage && data.webserver.bgImage.length > 0) {
$("#bg-image").val(data.webserver.bgImage);
}
if(Array.isArray(data.webserver.presets)) {
$('#preset1').val(data.webserver.presets[0] || "");
@@ -204,7 +240,18 @@ function submitData() {
$("#audio-quality").val(selectedQuality.text());
}
var antennaNames = ['ant1', 'ant2', 'ant3', 'ant4'];
// Iterate over each antenna name
antennaNames.forEach(function(antenna) {
// Set values based on the antenna name
$('#' + antenna + '-name').val(data.antennas?.[antenna]?.name || '');
$('#' + antenna + '-enabled').prop("checked", data.antennas?.[antenna]?.enabled || false);
});
$('#audio-software-mode').prop("checked", data.audio.softwareMode || false);
$('#startup-volume').val(data.audio.startupVolume || 100);
$('#volume-percentage-value').text(data.audio.startupVolume !== undefined ? (data.audio.startupVolume * 100).toFixed(0) + '%' : '100%');
$('#webserver-name').val(data.identification.tunerName);
$('#webserver-desc').val(data.identification.tunerDesc);
@@ -220,7 +267,7 @@ function submitData() {
$("#tuner-public").prop("checked", data.publicTuner);
$("#tuner-lock").prop("checked", data.lockToAdmin);
$("#shutdown-tuner").prop("checked", data.autoShutdown);
$("#antenna-switch").prop("checked", data.antennaSwitch);
$("#antenna-switch").prop("checked", data.antennas?.enabled);
// Check if latitude and longitude are present in the data
if (data.identification.lat && data.identification.lon) {

View File

@@ -19,11 +19,18 @@ const toggleDropdown = (event) => {
const selectOption = (event) => {
const $currentDropdown = currentDropdown;
if($currentDropdown.attr('id') == 'data-ant') {
socket.send("Z" + $(event.currentTarget).attr('data-value'));
tuneTo(getCurrentFreq()); //Reset RDS when change antenna input
} else {
$currentDropdown.find('input').val($(event.currentTarget).text());
switch($currentDropdown.attr('id')) {
case 'data-ant':
socket.send("Z" + $(event.currentTarget).attr('data-value'));
tuneTo(getCurrentFreq()); //Reset RDS when change antenna input
break;
case 'data-bw':
socket.send("W" + $(event.currentTarget).attr('data-value'));
$currentDropdown.find('input').val($(event.currentTarget).text());
break;
default:
$currentDropdown.find('input').val($(event.currentTarget).text());
break;
}
// Use setTimeout to delay class removal

View File

@@ -14,6 +14,7 @@ function getInitialSettings() {
localStorage.setItem('preset2', data.presets[1]);
localStorage.setItem('preset3', data.presets[2]);
localStorage.setItem('preset4', data.presets[3]);
localStorage.setItem('bgImage', data.bgImage);
},
error: function (error) {
console.error('Error:', error);

View File

@@ -41,7 +41,6 @@ $(document).ready(function () {
$panel.css('left', -panelWidth);
}
});
canvas.width = canvas.parentElement.clientWidth;
canvas.height = canvas.parentElement.clientHeight;
@@ -611,6 +610,7 @@ function updateDataElements(parsedData) {
const $dataRt0 = $('#data-rt0');
const $dataRt1 = $('#data-rt1');
const $dataAntInput = $('#data-ant input');
const $dataBwInput = $('#data-bw input');
const $dataStationContainer = $('#data-station-container');
const $dataTp = $('.data-tp');
const $dataTa = $('.data-ta');
@@ -641,6 +641,7 @@ function updateDataElements(parsedData) {
$('.data-flag-big').html(`<i title="${parsedData.country_name}" class="flag-md flag-md-${parsedData.country_iso}"></i>`);
$dataAntInput.val($('#data-ant li[data-value="' + parsedData.ant + '"]').text());
$dataBwInput.val($('#data-bw li[data-value="' + parsedData.bw + '"]').text());
if (parsedData.txInfo.station.length > 1) {
$('#data-station-name').text(parsedData.txInfo.station.replace(/%/g, '%25'));

View File

@@ -1,9 +1,9 @@
var currentDate = new Date('March 21, 2024 22:00:00');
var currentDate = new Date('March 24, 2024 19:00:00');
var day = currentDate.getDate();
var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1
var year = currentDate.getFullYear();
var formattedDate = day + '/' + month + '/' + year;
var currentVersion = 'v1.1.6 [' + formattedDate + ']';
var currentVersion = 'v1.1.7 [' + formattedDate + ']';
/**
@@ -52,6 +52,7 @@ var currentVersion = 'v1.1.6 [' + formattedDate + ']';
setTheme(selectedTheme);
themeSelector.find('input').val($(event.target).text()); // Set the text of the clicked option to the input
localStorage.setItem('theme', selectedTheme);
setBg();
});
// Signal Selector
@@ -156,6 +157,8 @@ var currentVersion = 'v1.1.6 [' + formattedDate + ']';
});
$('.version-string').text(currentVersion);
setBg();
});
@@ -177,3 +180,10 @@ var currentVersion = 'v1.1.6 [' + formattedDate + ']';
}
}
function setBg() {
if(localStorage.getItem('bgImage').length > 1 && localStorage.getItem('theme') != 'theme8') {
$('body').css('background', 'url(' + localStorage.getItem('bgImage') + ') var(--color-main)');
} else {
$('body').css('background', 'var(--color-main)');
}
}

View File

@@ -9,6 +9,13 @@ $(document).ready(function() {
MapCreate();
fetchData();
$('#startup-volume').on('change', function() {
console.log('changed');
var value = $(this).val(); // Get the value of the range input
var percentage = value * 100; // Convert to percentage
$('#volume-percentage-value').text(percentage.toFixed(0) + '%'); // Display the percentage value
});
map.on('click', function(ev) {
$('#lat').val((ev.latlng.lat).toFixed(6));
$('#lng').val((ev.latlng.lng).toFixed(6));

View File

@@ -248,38 +248,78 @@
<div class="panel-100 tab-content" id="webserver">
<h2>Webserver settings</h2>
<div class="flex-container">
<div class="panel-50 no-bg">
<div class="panel-100 no-bg">
<h3>Background image</h3>
<div class="form-group">
<label for="bg-image">Image link:</label>
<input class="input-text w-200" type="text" placeholder="" name="bg-image" id="bg-image">
</div>
</div>
<div class="panel-100 no-bg">
<h3>Themes</h3>
<div class="form-group">
<label for="themes"><i class="fa-solid fa-palette"></i>Default server theme:</label>
<div class="dropdown" id="server-theme-selector" style="margin-right: 0;">
<input type="text" placeholder="Default" id="selected-theme" readonly>
<ul class="options">
<li class="option" data-value="theme1">Default</li>
<li class="option" data-value="theme2">Cappuccino</li>
<li class="option" data-value="theme3">Nature</li>
<li class="option" data-value="theme4">Ocean</li>
<li class="option" data-value="theme5">Terminal</li>
<li class="option" data-value="theme6">Nightlife</li>
<li class="option" data-value="theme7">Blurple</li>
<li class="option" data-value="theme8">Construction</li>
<li class="option" data-value="theme9">AMOLED</li>
</ul>
</div>
</div>
</div>
</div>
<div class="panel-50 no-bg">
<h3>Antenna options</h3>
<div class="form-group checkbox bottom-20">
<input type="checkbox" id="antenna-switch">
<label for="antenna-switch">Enable the antenna switch</label>
</div>
</div>
<div class="panel-50 no-bg">
<h3>Chat options</h3>
<div class="form-group checkbox bottom-20">
<input type="checkbox" id="chat-switch">
<label for="chat-switch">Enable chat</label>
</div>
</div>
</div>
</div><br>
<div class="form-group checkbox">
<input type="checkbox" id="ant1-enabled">
<label for="ant1-enabled"></label>
</div>
<div class="form-group">
<label for="ant1-name">Antenna 1 name:</label>
<input class="input-text w-100" type="text" placeholder="Ant A" name="ant1-name" id="ant1-name">
</div><br>
<div class="form-group checkbox">
<input type="checkbox" id="ant2-enabled">
<label for="ant2-enabled"></label>
</div>
<div class="form-group">
<label for="ant2-name">Antenna 2 name:</label>
<input class="input-text w-100" type="text" placeholder="Ant B" name="ant2-name" id="ant2-name">
</div><br>
<div class="form-group checkbox">
<input type="checkbox" id="ant3-enabled">
<label for="ant3-enabled"></label>
</div>
<div class="form-group">
<label for="ant3-name">Antenna 3 name:</label>
<input class="input-text w-100" type="text" placeholder="Ant C" name="ant3-name" id="ant3-name">
</div><br>
<div class="form-group checkbox">
<input type="checkbox" id="ant3-enabled">
<label for="ant4-enabled"></label>
</div>
<div class="form-group">
<label for="ant4-name">Antenna 4 name:</label>
<input class="input-text w-100" type="text" placeholder="Ant D" name="ant4-name" id="ant4-name">
</div><br>
<h3>Themes</h3>
<div class="form-group">
<label for="themes"><i class="fa-solid fa-palette"></i>Default server theme:</label>
<div class="dropdown" id="server-theme-selector" style="margin-right: 0;">
<input type="text" placeholder="Default" id="selected-theme" readonly>
<ul class="options">
<li class="option" data-value="theme1">Default</li>
<li class="option" data-value="theme2">Cappuccino</li>
<li class="option" data-value="theme3">Nature</li>
<li class="option" data-value="theme4">Ocean</li>
<li class="option" data-value="theme5">Terminal</li>
<li class="option" data-value="theme6">Nightlife</li>
<li class="option" data-value="theme7">Blurple</li>
<li class="option" data-value="theme8">Construction</li>
<li class="option" data-value="theme9">AMOLED</li>
</ul>
</div>
</div>
<br><hr>
@@ -337,13 +377,23 @@
<br><hr>
<h3>Banlist</h3>
<p>If you have users that don't behave in your chat, you can choose to ban them by their IP address.<br>
<span class="text-gray">You can see their IP address by hovering over their nickname. One IP per row.</span></p>
<div class="form-group">
<label for="preset1">Banned users:</label>
<textarea id="ip-addresses" placeholder="123.45.67.8"></textarea>
</div>
<div class="panel-100 no-bg">
<h3>Chat options</h3>
<div class="form-group checkbox bottom-20">
<input type="checkbox" id="chat-switch">
<label for="chat-switch">Enable chat</label>
</div>
</div>
<div class="panel-100 no-bg">
<h3>Banlist</h3>
<p>If you have users that don't behave in your chat, you can choose to ban them by their IP address.<br>
<span class="text-gray">You can see their IP address by hovering over their nickname. One IP per row.</span></p>
<div class="form-group">
<label for="preset1">Banned users:</label>
<textarea id="ip-addresses" placeholder="123.45.67.8"></textarea>
</div>
</div>
</div>
@@ -357,10 +407,25 @@
<li class="option" data-value="tef">TEF668x / TEA685x</li>
<li class="option" data-value="xdr">XDR (F1HD / S10HDiP)</li>
<li class="option" data-value="sdr">SDR (RTL-SDR / AirSpy)</li>
<li class="option" data-value="sdr">Other</li>
<li class="option" data-value="other">Other</li>
</ul>
</div>
</div><br>
<div class="form-group checkbox">
<input type="checkbox" id="toggle-bw">
<label for="toggle-bw">Toggle bandwidth switch</label>
</div><br>
<h3>Startup Volume</h3>
<div class="panel-50 bg-color-2 auto" style="padding: 20px;">
<div class="panel-75 auto" style="height: 48px;">
<input type="range" id="startup-volume" min="0" max="1" step="0.01" value="1" aria-label="Startup Volume slider">
</div>
<h3 class="top-25" id="volume-percentage-value">asdf</hš>
</div>
</div>
<div class="panel-100 tab-content" id="identification">