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

design changes, accessibility stuff

This commit is contained in:
NoobishSVK
2024-07-18 14:57:43 +02:00
parent 3a6deecc02
commit 3d608ae8e8
17 changed files with 259 additions and 138 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "fm-dx-webserver",
"version": "1.2.3",
"version": "1.2.4",
"description": "FM DX Webserver",
"main": "index.js",
"scripts": {

View File

@@ -4,6 +4,7 @@ const fetch = require('node-fetch');
const { logDebug, logError, logInfo, logWarn } = require('./console');
const { serverConfig, configUpdate, configSave } = require('./server_config');
var pjson = require('../package.json');
var os = require('os');
let timeoutID = null;
@@ -60,6 +61,7 @@ function sendKeepalive() {
}
function sendUpdate() {
let currentOs = os.type() + ' ' + os.release();
let bwLimit = '';
if (serverConfig.webserver.tuningLimit === true) {
@@ -76,7 +78,8 @@ function sendUpdate() {
contact: serverConfig.identification.contact || '',
tuner: serverConfig.device || '',
bwLimit: bwLimit,
version: pjson.version
os: currentOs,
version: pjson.version
};
if (serverConfig.identification.token)

View File

@@ -47,7 +47,7 @@ h4 {
color: var(--color-text);
text-align: center;
font-size: 14px;
border-radius: 30px;
border-radius: 15px;
padding: 5px 25px;
z-index: 1000;
opacity: 0;
@@ -86,6 +86,7 @@ label {
#data-ps {
font-weight: 500;
margin-top: -5px;
}
#data-station-container {
@@ -254,28 +255,28 @@ label {
}
.admin-quick-dashboard {
position: absolute;
top: 0;
bottom: 0;
left: -96px;
width: 96px;
height: 286px;
width: 255px;
height: 72px;
background-color: var(--color-2);
margin: auto 0;
border-radius: 30px;
padding-top: 15px;
margin: 0 auto;
margin-bottom: 15px;
padding: 5px;
border-radius: 15px;
display: flex;
align-items: center;
justify-content: center;
}
.admin-quick-dashboard .icon {
width: 72px;
height: 72px;
margin: 10px auto;
width: 52px;
height: 52px;
margin: auto;
color: var(--color-1);
background-color: var(--color-3);
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
font-size: 18px;
border-radius: 10px;
transition: 0.3s ease-in-out background-color;
cursor: pointer;
@@ -293,6 +294,30 @@ pre {
color: white;
}
.circle-container {
position: relative;
width: 25px;
height: 34px;
}
.circle {
position: absolute;
width: 16px;
height: 16px;
border: 2px solid var(--color-3);
border-radius: 50%;
}
.circle.circle1 {
left: 0px;
top: 10px;
}
.circle.circle2 {
left: 8px;
top: 10px;
}
@media (max-width: 768px) {
canvas, #flags-container {
display: none;
@@ -442,4 +467,10 @@ pre {
.chatbutton {
height: 88px !important;
}
}
@media only screen and (min-width: 769px) and (max-height: 610px) {
.canvas-container {
display: none;
}
}

View File

@@ -2,7 +2,7 @@ button, input[type="submit"] {
width: 100%;
height: 100%;
border: 0;
border-radius: 30px;
border-radius: 15px;
transition: 0.3s ease-in-out background-color;
background-color: var(--color-4);
cursor: pointer;
@@ -40,7 +40,7 @@ button:hover {
height: 64px;
background: var(--color-2);
color: var(--color-main);
border-radius: 30px;
border-radius: 15px;
margin-right: 10px;
margin-left: 10px;
display: flex;
@@ -112,11 +112,11 @@ input[type="text"], textarea, input[type="password"] {
}
#freq-down {
border-radius: 30px 0 0 30px;
border-radius: 15px 0 0 15px;
}
#freq-up {
border-radius: 0 30px 30px 0;
border-radius: 0 15px 15px 0;
}
input[type="range"] {
@@ -130,7 +130,7 @@ input[type="range"] {
outline: none;
/* slider progress trick */
overflow: hidden;
border-radius: 30px;
border-radius: 15px;
height: 100%;
background: transparent;
}
@@ -139,7 +139,7 @@ input[type="range"] {
input[type="range"]::-moz-range-track {
height: 48px;
background: var(--color-1);
border-radius: 30px;
border-radius: 15px;
border: 0;
}
@@ -153,7 +153,7 @@ input[type="range"]::-webkit-slider-thumb {
background: url('../images/speaker.svg') center no-repeat, var(--color-5);
background-position: center;
background-size: 20px;
border-radius: 30px;
border-radius: 15px;
outline: 4px solid var(--color-5);
outline-offset: -3px;
/* slider progress trick */
@@ -168,7 +168,7 @@ input[type="range"]::-moz-range-thumb {
background: url('../images/speaker.svg') center no-repeat, var(--color-5);
background-position: center;
background-size: 20px;
border-radius: 30px;
border-radius: 15px;
outline: 4px solid var(--color-5);
outline-offset: -3px;
/* slider progress trick */
@@ -279,7 +279,7 @@ input[type="range"]::-moz-range-thumb {
position: absolute;
left: 0;
top: -2px;
border-radius: 30px;
border-radius: 15px;
-webkit-transition: all 0.2s ease-out;
-moz-transition: all 0.2s ease-out;
transition: all 0.2s ease-out;

View File

@@ -242,7 +242,7 @@
display: none;
}
.m-0 {
margin: auto;
margin: auto !important;
}
}

View File

@@ -46,19 +46,31 @@ body {
font-family: 'Titillium Web', sans-serif;
color: var(--color-text);
background: var(--color-main);
background-blend-mode: multiply;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
transition: 0.3s ease-in-out background-color;
margin: 0 auto;
min-height: 100%;
}
#wrapper-outer {
width: 100%;
height: auto;
background-color: var(--color-main);
display: flex;
align-items: center;
justify-content: center;
min-height:100vh;
}
.wrapper-outer-static {
display: block !important;
padding-top: 10px;
padding-bottom: 10px;
}
#wrapper {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 1180px;
max-width: 1180px;
}
@@ -82,7 +94,7 @@ hr {
}
.table-big {
border-radius: 30px;
border-radius: 15px;
background-color: var(--color-2);
padding: 20px;
margin: auto;
@@ -109,11 +121,11 @@ hr {
.table-big th:nth-child(1) {
border-radius: 30px 0px 0px 30px;
border-radius: 15px 0px 0px 15px;
}
.table-big th:nth-last-child(1){
border-radius: 0px 30px 30px 0px;
border-radius: 0px 15px 15px 0px;
}
@media (max-width: 1180px) {

View File

@@ -22,7 +22,7 @@
transform: translate(-50%, -50%);
background-color: var(--color-main);
padding: 30px;
border-radius: 30px;
border-radius: 15px;
opacity: 1;
transition: opacity 0.3s ease-in-out; /* Fade-in/out transition */
z-index: 21; /* Ensure the modal content is above the modal background */
@@ -56,7 +56,7 @@
right: 35px;
width: 100px;
height: 48px;
border-radius: 30px;
border-radius: 15px;
background: var(--color-4);
font-weight: bold;
border: 0;
@@ -135,12 +135,12 @@
text-align: center;
display: none;
background-color: var(--color-main);
border-radius: 30px 30px 0px 0px;
border-radius: 15px 15px 0px 0px;
}
.modal-panel-chat .modal-panel-sidebar {
width: 100%;
border-radius: 30px 30px 0px 0px;
border-radius: 15px 15px 0px 0px;
}
@media only screen and (max-width: 768px) {

View File

@@ -3,7 +3,7 @@
height: 320px;
background-color: var(--color-2);
padding: 8px 16px;
border-radius: 30px;
border-radius: 15px;
padding: 20px;
}

View File

@@ -2,15 +2,14 @@
background-color: var(--color-1);
margin-left: 10px;
margin-right: 10px;
border-radius: 30px;
border-radius: 15px;
text-align: center;
margin-top: 30px;
margin-top: 20px;
transition: 0.3s ease-in-out background-color;
}
.panel-10 {
width: 10%;
margin-top: 30px;
}
.panel-33 {

View File

@@ -30,7 +30,7 @@ ul.nav {
list-style-type: none;
padding: 15px 0;
background: var(--color-2);
border-radius: 30px;
border-radius: 15px;
}
ul.nav li {
@@ -98,7 +98,7 @@ li.active {
color: var(--color-main);
margin: 0px 10px;
padding: 15px 35px;
border-radius: 30px;
border-radius: 15px;
min-width: fit-content;
}
}

View File

@@ -36,9 +36,10 @@
</script>
</head>
<body>
<div id="wrapper-outer">
<div id="wrapper">
<div class="panel-100 no-bg tuner-info">
<h1 id="tuner-name"><%= tunerName %>
<h1 id="tuner-name"><span class="text-bold" style="color: var(--color-text);">[</span> <%= tunerName %> <span class="text-bold" style="color: var(--color-text);">]</span>
<% if (!publicTuner) { %><i class="fa-solid fa-key pointer tooltip" aria-label="Only people with tune password can tune." data-tooltip="Only people with tune password can tune."></i>
<% } if (tunerLock) { %><i class="fa-solid fa-lock pointer tooltip" aria-label="Tuner is currently locked to admin." data-tooltip="Tuner is currently locked to admin."></i>
<% } %>
@@ -56,7 +57,7 @@
</div>
<div class="flex-container">
<div class="panel-100 bg-none" style="margin-top: 0;">
<div class="panel-100 bg-none" style="margin-top: 0; margin-left: 0;">
<div class="flex-container">
<div class="panel-75 flex-container no-bg">
<div class="panel-10 no-bg h-100 m-0 m-right-20 hide-phone" style="width: 100px;margin-right: 20px !important;">
@@ -77,8 +78,11 @@
<div style="display:inline-block">
<span style="margin-left: 20px;display: block;margin-top: 2px;" class="data-flag"></span>
</div>
<span class="pointer stereo-container" style="position: relative;">
<span style="margin-left: 20px;" class="data-st">ST</span>
<span class="pointer stereo-container" style="position: relative;" role="button" aria-label="Stereo / Mono toggle" tabindex="0">
<div class="circle-container">
<div class="circle data-st circle1"></div>
<div class="circle data-st circle2"></div>
</div>
<span class="overlay tooltip" data-tooltip="Stereo / Mono toggle. <br><strong>Click to toggle."></span>
</span>
<span style="margin-left: 15px;" class="data-ms">MS</span>
@@ -132,12 +136,12 @@
<% } %>
<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><% } %>
<% if (device == 'tef') { %><button id="data-eq" style="border-radius: 15px 0px 0px 15px;" 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: 15px 0px 0px 15px;" 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-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><% } %>
<% if (device == 'tef') { %><button id="data-ims" style="border-radius: 0px 15px 15px 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 15px 15px 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>
</div>
</div>
@@ -275,17 +279,20 @@
</div>
<div class="panel-10 bg-none" style="margin-top: 0;">
<div class="panel-100 w-100">
<div class="panel-10 bg-none m-0">
<div class="panel-100 w-100" style="margin-left: 0;">
<h2>AF</h2>
<div id="af-list" class="p-bottom-20" style="text-align: center;">
<ul style="height: 251px;">
<% if (chatEnabled) { %><ul style="height: 231px;">
<% } else { %>
<ul style="height: 351px;">
<% } %>
</ul>
</div>
</div>
<% if (chatEnabled) { %>
<div class="panel-10 no-bg h-100 hide-phone" style="width: 100px; height: 100px;">
<div class="panel-10 no-bg h-100 hide-phone" style="width: 100px; height: 100px; margin-left: 0;">
<button class="chatbutton bg-color-2" aria-label="Chatbox"><i class="fa-solid fa-comments fa-lg"></i> (<span class="chat-messages-count">0</span>)</button>
</div>
<% } %>
@@ -302,7 +309,10 @@
<span style="margin-left: 20px;display: block;margin-top: 2px;" class="data-flag"></span>
</div>
<span class="pointer stereo-container" style="position: relative;">
<span style="margin-left: 20px;" class="data-st">ST</span>
<div class="circle-container">
<div class="circle data-st circle1"></div>
<div class="circle data-st circle2"></div>
</div>
<span class="overlay tooltip" data-tooltip="Stereo / Mono toggle. <br><strong>Click to toggle."></span>
</span>
<span style="margin-left: 15px;" class="data-ms">MS</span>
@@ -312,28 +322,14 @@
<button id="settings" aria-label="Settings"><i class="fa-solid fa-gear"></i></button>
<% if (chatEnabled) { %>
<button class="chatbutton hide-desktop bg-color-2"><i class="fa-solid fa-comments fa-lg"></i> (<span class="chat-messages-count">0</span>)</button>
<button class="chatbutton hide-desktop bg-color-2" aria-label="Chatbox"><i class="fa-solid fa-comments fa-lg"></i> (<span class="chat-messages-count">0</span>)</button>
<% } %>
<button id="users-online-container" class="hide-phone" aria-label="Online users"><i class="fa-solid fa-user"></i> <span class="users-online"></span></button>
<% if (isAdminAuthenticated) { %>
<div class="admin-quick-dashboard hide-phone">
<div class="icon tooltip <% if (tunerLock) { %>active<% } %>" id="dashboard-lock-admin" onClick="toggleAdminLock()" data-tooltip="Toggle admin lock<br>Lasts until restart">
<i class="fa-solid fa-lock"></i>
</div>
<div class="icon tooltip <% if (!publicTuner) { %>active<% } %>" id="dashboard-lock-tune" onClick="togglePasswordLock()" data-tooltip="Toggle password lock<br>Lasts until restart">
<i class="fa-solid fa-key"></i>
</div>
<div class="icon tooltip" data-tooltip="Go to admin menu" onClick="window.open('./setup', '_blank').focus();">
<i class="fa-solid fa-user"></i>
</div>
</div>
<% } %>
<button id="users-online-container" class="hide-phone" aria-label="Online users"><i class="fa-solid fa-user"></i> <span class="users-online"></span></button>
<div id="myModal" class="modal">
<div class="modal-panel">
<div class="flex-container flex-phone" style="height: calc(100% - 100px)">
<div class="modal-panel-sidebar hover-brighten flex-center text-medium-big closeModal" role="button" aria-label="Close settings"><i class="fa-solid fa-chevron-right"></i></div>
<div class="modal-panel-sidebar hover-brighten flex-center text-medium-big closeModal" role="button" aria-label="Close settings" tabindex="0"><i class="fa-solid fa-chevron-right"></i></div>
<div class="modal-panel-content">
<h1 class="top-25">Settings</h1>
@@ -370,11 +366,11 @@
<% } %>
<div class="form-group checkbox">
<input type="checkbox" id="extended-frequency-range">
<input type="checkbox" tabindex="0" id="extended-frequency-range">
<label for="extended-frequency-range">Add decimals manually</label>
</div>
<div class="form-group checkbox">
<input type="checkbox" id="ps-underscores">
<input type="checkbox" tabindex="0" id="ps-underscores">
<label for="ps-underscores">Add underscores to RDS PS</label>
</div>
@@ -384,11 +380,28 @@
</div>
<% if (isAdminAuthenticated) { %>
<p>You are logged in as an adminstrator.<br>
<a href="./setup" target="_blank">Setup</a> • <a class="logout-link" href="#">Logout</a>
</p>
<p class="color-3">You are logged in as an adminstrator.</p>
<div class="admin-quick-dashboard">
<div class="icon tooltip <% if (tunerLock) { %>active<% } %>" id="dashboard-lock-admin" onClick="toggleAdminLock()" role="button" aria-label="Toggle admin lock until restart" tabindex="0" data-tooltip="Toggle admin lock<br>Lasts until restart">
<i class="fa-solid fa-lock"></i>
</div>
<div class="icon tooltip <% if (!publicTuner) { %>active<% } %>" id="dashboard-lock-tune" onClick="togglePasswordLock()" role="button" aria-label="Toggle password lock until restart" tabindex="0" data-tooltip="Toggle password lock<br>Lasts until restart">
<i class="fa-solid fa-key"></i>
</div>
<div class="icon tooltip" role="button" aria-label="Go to admin panel" tabindex="0" data-tooltip="Go to admin panel" onClick="window.open('./setup', '_blank').focus();">
<i class="fa-solid fa-user"></i>
</div>
<div class="icon tooltip logout-link" role="button" aria-label="Sign out" tabindex="0" data-tooltip="Sign out">
<i class="fa-solid fa-sign-out"></i>
</div>
</div>
<% } else if (isTuneAuthenticated) { %>
<p>You are logged in and can control the receiver.<br><a class="logout-link" href="#">Logout</a></p>
<p class="color-3">You are logged in and can control the receiver.<br><a class="logout-link" href="#">Logout</a></p>
<div class="admin-quick-dashboard">
<div class="icon tooltip logout-link" role="button" aria-label="Sign out" tabindex="0" data-tooltip="Sign out">
<i class="fa-solid fa-sign-out"></i>
</div>
</div>
<% } else { %>
<form action="./login" method="post" id="login-form" class="top-25">
<label for="password">Password:</label>
@@ -396,7 +409,7 @@
<button type="submit" class="br-0 w-100 top-10" style="height: 44px">Login</button>
</form>
<% } %>
<div id="login-message"></div>
<div id="login-message" class="color-3"></div>
<hr class="color-2 auto">
@@ -465,7 +478,7 @@
</div>
<div class="modal-panel-chat">
<div class="modal-panel-sidebar hover-brighten flex-center text-medium-big closeModal" role="button" aria-label="Close chat"><i class="fa-solid fa-chevron-down"></i></div>
<div class="modal-panel-sidebar hover-brighten flex-center text-medium-big closeModal" role="button" aria-label="Close chat" tabindex="0"><i class="fa-solid fa-chevron-down"></i></div>
<div class="modal-panel-content text-left">
<div style="text-align: center;">
<input type="text" id="chat-nickname" name="chat-nickname" placeholder="Nickname">
@@ -485,6 +498,7 @@
</div>
</div>
</div>
</div>
<script src="js/websocket.js"></script>
<script src="js/webserver.js"></script>

View File

@@ -1,9 +1,9 @@
var currentDate = new Date('Jul 15, 2024 23:00:00');
var currentDate = new Date('Jul 18, 2024 15: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.2.3 [' + formattedDate + ']';
var currentVersion = 'v1.2.4 [' + formattedDate + ']';
getInitialSettings();

View File

@@ -239,6 +239,7 @@ function initCanvas(parsedData) {
maxDataPoints,
pointWidth,
color2: null,
color3: null,
color4: null,
signalUnit: localStorage.getItem('signalUnit'),
offset: 0,
@@ -264,9 +265,11 @@ function initCanvas(parsedData) {
function updateChartSettings(signalChart) {
// Update colors
const newColor2 = getComputedStyle(document.documentElement).getPropertyValue('--color-2').trim();
const newColor3 = getComputedStyle(document.documentElement).getPropertyValue('--color-3').trim();
const newColor4 = getComputedStyle(document.documentElement).getPropertyValue('--color-4').trim();
if (newColor2 !== signalChart.color2 || newColor4 !== signalChart.color4) {
signalChart.color2 = newColor2;
signalChart.color3 = newColor3;
signalChart.color4 = newColor4;
}
@@ -284,7 +287,7 @@ function updateChartSettings(signalChart) {
}
function updateCanvas(parsedData, signalChart) {
const { context, canvas, maxDataPoints, pointWidth, color2, color4, offset } = signalChart;
const { context, canvas, maxDataPoints, pointWidth, color2, color3, color4, offset } = signalChart;
if (data.length > maxDataPoints) {
data = data.slice(data.length - maxDataPoints);
@@ -319,11 +322,11 @@ function updateCanvas(parsedData, signalChart) {
}
context.strokeStyle = color4;
context.lineWidth = 1;
context.lineWidth = 2;
context.stroke();
// Draw horizontal lines for lowest, highest, and average values
context.strokeStyle = color2;
context.strokeStyle = color3;
context.lineWidth = 1;
// Draw the lowest value line
@@ -422,6 +425,10 @@ function getCurrentFreq() {
function checkKey(e) {
e = e || window.event;
if (e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) {
return;
}
if ($('#password:focus').length > 0
|| $('#chat-send-message:focus').length > 0
|| $('#volumeSlider:focus').length > 0
@@ -706,7 +713,18 @@ const updateDataElements = throttle(function(parsedData) {
}
updateHtmlIfChanged($dataPs, parsedData.ps === '?' ? "<span class='opacity-half'>?</span>" : processString(parsedData.ps, parsedData.ps_errors));
updateHtmlIfChanged($dataSt, `<span class='opacity-${parsedData.st ? 'full' : 'half'}'>${parsedData.st_forced ? 'MO' : 'ST'}</span>`);
let stereoColor;
if(parsedData.st) {
stereoColor = 'var(--color-4)';
} else {
stereoColor = 'var(--color-3)';
}
if(parsedData.st_forced) {
stereoColor = 'gray';
}
$dataSt.css('border', '2px solid ' + stereoColor);
//updateHtmlIfChanged($dataSt, `<span class='opacity-${parsedData.st ? 'full' : 'half'}'>${parsedData.st_forced ? 'MO' : 'ST'}</span>`);
updateHtmlIfChanged($dataRt0, processString(parsedData.rt0, parsedData.rt0_errors));
updateHtmlIfChanged($dataRt1, processString(parsedData.rt1, parsedData.rt1_errors));

View File

@@ -1,19 +1,20 @@
/**
* Themes
* @param first color
* @param second color
* @param main color
* @param main-bright color
* @param text color
* @param background filter color
*/
const themes = {
theme1: ['rgba(32, 34, 40, 1)', 'rgba(88, 219, 171, 1)', 'rgba(255, 255, 255, 1)' ], // Retro (Default)
theme2: [ 'rgba(21, 32, 33, 1)', 'rgba(203, 202, 165, 1)', 'rgba(255, 255, 255, 1)' ], // Cappuccino
theme3: [ 'rgba(18, 18, 12, 1)', 'rgba(169, 255, 112, 1)', 'rgba(255, 255, 255, 1)' ], // Nature
theme4: [ 'rgba(12, 28, 27, 1)', 'rgba(104, 247, 238, 1)', 'rgba(255, 255, 255, 1)' ], // Ocean
theme5: [ 'rgba(23, 17, 6, 1)', 'rgba(245, 182, 66, 1)', 'rgba(255, 255, 255, 1)' ], // Terminal
theme6: [ 'rgba(33, 9, 29, 1)', 'rgba(250, 82, 141, 1)', 'rgba(255, 255, 255, 1)' ], // Nightlife
theme7: [ 'rgba(13, 11, 26, 1)', 'rgba(128, 105, 250, 1)', 'rgba(255, 255, 255, 1)' ], // Blurple
theme8: [ 'rgba(252, 186, 3, 1)', 'rgba(0, 0, 0, 1)', 'rgba(0, 0, 0, 1)' ], // Construction
theme9: [ 'rgba(0, 0, 0, 1)', 'rgba(204, 204, 204, 1)', 'rgba(255, 255, 255, 1)' ], // AMOLED
theme1: [ 'rgba(32, 34, 40, 1)', 'rgba(88, 219, 171, 1)', 'rgba(255, 255, 255, 1)', 'rgba(11, 12, 14, 1)' ], // Retro (Default)
theme2: [ 'rgba(21, 32, 33, 1)', 'rgba(203, 202, 165, 1)', 'rgba(255, 255, 255, 1)', 'rgba(7, 11, 12, 1)' ], // Cappuccino
theme3: [ 'rgba(18, 18, 12, 1)', 'rgba(169, 255, 112, 1)', 'rgba(255, 255, 255, 1)', 'rgba(6, 6, 4, 1)' ], // Nature
theme4: [ 'rgba(12, 28, 27, 1)', 'rgba(104, 247, 238, 1)', 'rgba(255, 255, 255, 1)', 'rgba(4, 10, 9, 1)' ], // Ocean
theme5: [ 'rgba(23, 17, 6, 1)', 'rgba(245, 182, 66, 1)', 'rgba(255, 255, 255, 1)', 'rgba(8, 6, 2, 1)' ], // Terminal
theme6: [ 'rgba(33, 9, 29, 1)', 'rgba(250, 82, 141, 1)', 'rgba(255, 255, 255, 1)', 'rgba(12, 3, 10, 1)' ], // Nightlife
theme7: [ 'rgba(13, 11, 26, 1)', 'rgba(128, 105, 250, 1)', 'rgba(255, 255, 255, 1)', 'rgba(5, 4, 7, 1)' ], // Blurple
theme8: [ 'rgba(252, 186, 3, 1)', 'rgba(0, 0, 0, 1)', 'rgba(0, 0, 0, 1)', 'rgba(252, 186, 3, 1)' ], // Construction
theme9: [ 'rgba(0, 0, 0, 1)', 'rgba(204, 204, 204, 1)', 'rgba(255, 255, 255, 1)', 'rgba(0, 0, 0, 1)' ], // AMOLED
};
// Signal Units
@@ -141,22 +142,27 @@ $(document).ready(() => {
function setTheme(themeName) {
const themeColors = themes[themeName];
if (themeColors) {
// Extracting the RGBA components and opacity value
const rgbaComponents = themeColors[2].match(/(\d+(\.\d+)?)/g);
const opacity = parseFloat(rgbaComponents[3]);
const newOpacity = opacity * 0.75;
// Constructing the new RGBA string with the adjusted opacity
const textColor2 = `rgba(${rgbaComponents[0]}, ${rgbaComponents[1]}, ${rgbaComponents[2]}, ${newOpacity})`;
// Extracting the RGBA components from themeColors[2] for --color-text-2
const rgbaComponentsText = themeColors[2].match(/(\d+(\.\d+)?)/g);
const opacityText = parseFloat(rgbaComponentsText[3]);
const newOpacityText = opacityText * 0.75;
const textColor2 = `rgba(${rgbaComponentsText[0]}, ${rgbaComponentsText[1]}, ${rgbaComponentsText[2]}, ${newOpacityText})`;
// Extracting the RGBA components from themeColors[0] for background color
const rgbaComponentsBackground = themeColors[3].match(/(\d+(\.\d+)?)/g);
const backgroundOpacity = 0.85;
const backgroundColorWithOpacity = `rgba(${rgbaComponentsBackground[0]}, ${rgbaComponentsBackground[1]}, ${rgbaComponentsBackground[2]}, ${backgroundOpacity})`;
$(':root').css('--color-main', themeColors[0]);
$(':root').css('--color-main-bright', themeColors[1]);
$(':root').css('--color-text', themeColors[2]);
$(':root').css('--color-text-2', textColor2);
$('#wrapper-outer').css('background-color', backgroundColorWithOpacity);
}
}
function setBg() {
if(localStorage.getItem('bgImage').length > 1 && localStorage.getItem('theme') != 'theme8') {
if(localStorage.getItem('bgImage').length > 1 && localStorage.getItem('theme') != 'theme9') {
$('body').css('background', 'url(' + localStorage.getItem('bgImage') + ') top center / cover fixed no-repeat var(--color-main)');
} else {
$('body').css('background', 'var(--color-main)');

View File

@@ -148,6 +148,40 @@ $(document).ready(function() {
if($("#console-output").length > 0) {
$("#console-output").scrollTop($("#console-output")[0].scrollHeight);
}
const $tabs = $('.nav li[role="presentation"]');
let currentTabIndex = 0;
function updateTabFocus(index) {
$tabs.each(function(i) {
const $link = $(this).find('a');
if (i === index) {
$(this).attr('aria-selected', 'true');
$link.attr('tabindex', '0').focus();
} else {
$(this).attr('aria-selected', 'false');
$link.attr('tabindex', '-1');
}
});
}
function handleKeyDown(event) {
if (event.key === 'ArrowRight') {
event.preventDefault();
currentTabIndex = (currentTabIndex + 1) % $tabs.length;
updateTabFocus(currentTabIndex);
} else if (event.key === 'ArrowLeft') {
event.preventDefault();
currentTabIndex = (currentTabIndex - 1 + $tabs.length) % $tabs.length;
updateTabFocus(currentTabIndex);
} else if (event.key === 'Enter') {
event.preventDefault();
$tabs.eq(currentTabIndex).find('a')[0].click();
}
}
updateTabFocus(currentTabIndex);
$tabs.on('keydown', handleKeyDown);
});
function MapCreate() {

View File

@@ -12,34 +12,36 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="wrapper-outer" class="wrapper-outer-static">
<div id="wrapper" class="setup-wrapper">
<% if (isAdminAuthenticated) { %>
<div class="panel-100 no-bg">
<img class="top-10" src="./images/openradio_logo_neutral.png" height="64px">
<h2 class="text-monospace text-light">[ADMIN PANEL]</h2>
</div>
<div class="panel-100">
<ul class="nav" role="tablist">
<li role="presentation" data-panel="dashboard">
<a href="#" role="tab" aria-controls="dashboard" aria-selected="true">Dashboard</a>
<div id="login-message"></div>
<div class="panel-100" style="border-radius: 15px 15px 0 0;">
<ul class="nav" role="tablist" style="border-radius: 15px 15px 0 0;">
<li role="presentation" data-panel="dashboard" aria-selected="true">
<a href="#" role="tab" tabindex="0" aria-controls="dashboard">Dashboard</a>
</li>
<li role="presentation" data-panel="tuner">
<a href="#" role="tab" aria-controls="tuner">Tuner</a>
<a href="#" role="tab" tabindex="-1" aria-controls="tuner">Tuner</a>
</li>
<li role="presentation" data-panel="connection">
<a href="#" role="tab" aria-controls="connection">Connection</a>
<a href="#" role="tab" tabindex="-1" aria-controls="connection">Connection</a>
</li>
<li role="presentation" data-panel="audio">
<a href="#" role="tab" aria-controls="audio">Audio</a>
<a href="#" role="tab" tabindex="-1" aria-controls="audio">Audio</a>
</li>
<li role="presentation" data-panel="webserver">
<a href="#" role="tab" aria-controls="webserver">Webserver</a>
<a href="#" role="tab" tabindex="-1" aria-controls="webserver">Webserver</a>
</li>
<li role="presentation" data-panel="plugins">
<a href="#" role="tab" aria-controls="plugins">Plugins</a>
<a href="#" role="tab" tabindex="-1" aria-controls="plugins">Plugins</a>
</li>
<li role="presentation" data-panel="identification">
<a href="#" role="tab" aria-controls="identification">Info & Map</a>
<a href="#" role="tab" tabindex="-1" aria-controls="identification">Info & Map</a>
</li>
<li role="presentation" class="logout-link text-gray">
<a href="./logout"><i class="fas fa-sign-out"></i></a>
@@ -47,8 +49,7 @@
</ul>
</div>
<div id="login-message"></div>
<div class="panel-100">
<div class="panel-100" style="margin-top: -20px; border-radius: 0 0 15px 15px;">
<div class="panel-100 tab-content" id="dashboard" role="tabpanel">
<h2>Dashboard</h2>
@@ -83,7 +84,7 @@
<% if (connectedUsers.length > 0) { %>
<% connectedUsers.forEach(user => { %>
<tr>
<td><%= user.ip %></td>
<td><a href="https://dnschecker.org/ip-location.php?ip=<%= user.ip %>" target="_blank"><%= user.ip %></a></td>
<td><%= user.location %></td>
<td><%= user.time %></td>
<td><a href="./kick?ip=<%= user.ip %>">Kick</a></td>
@@ -100,15 +101,15 @@
<h3>Maintenance</h3>
<div class="flex-container flex-center" style="margin: 30px;">
<div class="form-group checkbox">
<input type="checkbox" id="tuner-public">
<input type="checkbox" tabindex="0" id="tuner-public">
<label for="tuner-public">Public tuner (no password)</label>
</div>
<div class="form-group checkbox">
<input type="checkbox" id="tuner-lock">
<input type="checkbox" tabindex="0" id="tuner-lock">
<label for="tuner-lock">Admin lock [only admins can tune]</label>
</div>
<div class="form-group checkbox">
<input type="checkbox" id="shutdown-tuner">
<input type="checkbox" tabindex="0" id="shutdown-tuner">
<label for="shutdown-tuner">Auto-shutdown</label>
</div><br>
</div>
@@ -144,7 +145,7 @@
<div style="width: 300px;" class="auto top-10">
<label class="toggleSwitch nolabel" onclick="">
<input id="connection-type-toggle" type="checkbox"/>
<input id="connection-type-toggle" type="checkbox" tabindex="0" />
<a></a>
<span>
<span class="left-span">Direct</span>
@@ -254,7 +255,7 @@
</div>
<div class="form-group checkbox bottom-20">
<input type="checkbox" id="audio-software-mode">
<input type="checkbox" tabindex="0" id="audio-software-mode">
<label for="audio-software-mode">ALSA software mode (plughw) - LINUX ONLY</label>
</div>
</div>
@@ -295,12 +296,12 @@
<div class="panel-50 no-bg">
<h3>Antenna options</h3>
<div class="form-group checkbox bottom-20">
<input type="checkbox" id="antenna-switch">
<input type="checkbox" tabindex="0" id="antenna-switch">
<label for="antenna-switch">Enable the antenna switch</label>
</div><br>
<div class="form-group checkbox">
<input type="checkbox" id="ant1-enabled">
<input type="checkbox" tabindex="0" id="ant1-enabled">
<label for="ant1-enabled"></label>
</div>
<div class="form-group">
@@ -309,7 +310,7 @@
</div><br>
<div class="form-group checkbox">
<input type="checkbox" id="ant2-enabled">
<input type="checkbox" tabindex="0" id="ant2-enabled">
<label for="ant2-enabled"></label>
</div>
<div class="form-group">
@@ -318,7 +319,7 @@
</div><br>
<div class="form-group checkbox">
<input type="checkbox" id="ant3-enabled">
<input type="checkbox" tabindex="0" id="ant3-enabled">
<label for="ant3-enabled"></label>
</div>
<div class="form-group">
@@ -327,7 +328,7 @@
</div><br>
<div class="form-group checkbox">
<input type="checkbox" id="ant4-enabled">
<input type="checkbox" tabindex="0" id="ant4-enabled">
<label for="ant4-enabled"></label>
</div>
<div class="form-group">
@@ -343,7 +344,7 @@
<div class="panel-50 no-bg">
<h3>Tuning options</h3>
<div class="form-group checkbox">
<input type="checkbox" id="default-freq-enable">
<input type="checkbox" tabindex="0" id="default-freq-enable">
<label for="default-freq-enable">Enable default frequency for first client</label>
</div><br>
<div class="form-group">
@@ -354,7 +355,7 @@
<span class="text-gray">Enter frequencies in MHz.</span>
</p>
<div class="form-group checkbox">
<input type="checkbox" id="tuning-limit">
<input type="checkbox" tabindex="0" id="tuning-limit">
<label for="tuning-limit">Limit tuning</label>
</div><br>
<div class="form-group">
@@ -371,7 +372,7 @@
<h3>RDS Mode</h3>
<p>You can switch between American (RBDS) / Global (RDS) mode here.</p>
<div class="form-group checkbox bottom-20">
<input type="checkbox" id="rds-mode">
<input type="checkbox" tabindex="0" id="rds-mode">
<label for="rds-mode">Enable American Mode (RBDS)</label>
</div>
@@ -402,7 +403,7 @@
<div class="panel-100 no-bg">
<h3>Chat options</h3>
<div class="form-group checkbox bottom-20">
<input type="checkbox" id="chat-switch">
<input type="checkbox" tabindex="0" id="chat-switch">
<label for="chat-switch">Enable chat</label>
</div>
</div>
@@ -450,7 +451,7 @@
</div><br>
<div class="form-group checkbox">
<input type="checkbox" id="toggle-bw">
<input type="checkbox" tabindex="0" id="toggle-bw">
<label for="toggle-bw">Toggle bandwidth switch</label>
</div><br>
@@ -487,7 +488,7 @@
<p class="m-0 text-gray">If your location information is filled,<br>you can add your tuner to a public list.</p>
<p></p>
<div class="form-group checkbox">
<input type="checkbox" id="broadcast-tuner">
<input type="checkbox" tabindex="0" id="broadcast-tuner">
<label for="broadcast-tuner">Broadcast to map</label>
</div><br>
<div class="form-group">
@@ -499,7 +500,7 @@
<input class="input-text" type="text" name="broadcast-address" id="broadcast-address">
</div>
<p>Check your tuner at <strong><a href="https://list.fmdx.pl" target="_blank" class="color-4">list.fmdx.pl</a></strong>.</p>
<p>Check your tuner at <strong><a href="https://servers.fmdx.org" target="_blank" class="color-4">servers.fmdx.org</a></strong>.</p>
</div>
</div>
<br>
@@ -546,6 +547,7 @@
</div>
<% } %>
</div>
</div>
<script src="js/init.js"></script>
<script src="js/settings.js"></script>
<script src="js/dropdown.js"></script>

View File

@@ -12,6 +12,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="wrapper-outer">
<div id="wrapper" class="setup-wrapper">
<% if (isAdminAuthenticated) { %>
<div class="panel-100 no-bg">
@@ -188,7 +189,7 @@
<h3>Map broadcast:</h3>
<p class="m-0">If your location info is filled, you can add your tuner to a public list.</p>
<p class="m-0">The list is available at <strong><a href="https://list.fmdx.pl" target="_blank" class="color-4">list.fmdx.pl</a></strong>.</p>
<p class="m-0">The list is available at <strong><a href="https://servers.fmdx.org" target="_blank" class="color-4">servers.fmdx.org</a></strong>.</p>
<p class="text-gray">Only fill up your broadcast address if you are using a proxy. If you don't know what a proxy is, leave it empty.</p>
<div class="form-group checkbox">
@@ -247,6 +248,7 @@
</div>
<% } %>
</div>
</div>
<script src="js/settings.js"></script>
<script src="js/dropdown.js"></script>
<script src="js/setup.js"></script>