You've already forked fm-dx-webserver
mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-02-26 14:11:59 +01:00
UI changes
This commit is contained in:
10
README.md
10
README.md
@@ -54,10 +54,14 @@ Join our **Discord community** to get the latest development update info, share
|
||||
|
||||
5. Open your web browser and navigate to `http:/localhost:8080` to access the web interface.
|
||||
|
||||
## Dependencies
|
||||
## Utilized projects
|
||||
|
||||
This project utilizes the [librdsparser](https://github.com/kkonradpl/librdsparser) library for RDS parsing. Make sure to check out the library for more information.
|
||||
Pre-built version of this library is bundled with the webserver.
|
||||
This project utilizes these libraries:
|
||||
- [librdsparser](https://github.com/kkonradpl/librdsparser) library by Konrad Kosmatka for RDS parsing
|
||||
- [3LAS](https://github.com/jojobond/3LAS) library by JoJoBond for Low Latency Audio Streaming
|
||||
- [flat-flags](https://github.com/luishdez/flat-flags) library by luishdez for RDS country flags
|
||||
|
||||
All of these libraries are already bundled with the webserver.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -204,8 +204,8 @@ const clientUpdateIntervals = new Map(); // Store update intervals for each clie
|
||||
// Initialize the data object
|
||||
var dataToSend = {
|
||||
pi: '?',
|
||||
freq: 87.500,
|
||||
previousFreq: 87.500,
|
||||
freq: 87.500.toFixed(3),
|
||||
previousFreq: 87.500.toFixed(3),
|
||||
signal: 0,
|
||||
st: false,
|
||||
st_forced: false,
|
||||
|
||||
45
index.js
45
index.js
@@ -271,6 +271,48 @@ const authenticate = (req, res, next) => {
|
||||
app.set('view engine', 'ejs'); // Set EJS as the template engine
|
||||
app.set('views', path.join(__dirname, '/web'))
|
||||
|
||||
function parseMarkdown(parsed) {
|
||||
parsed = parsed.replace(/<\/?[^>]+(>|$)/g, '');
|
||||
|
||||
var grayTextRegex = /--(.*?)--/g;
|
||||
parsed = parsed.replace(grayTextRegex, '<span class="text-gray">$1</span>');
|
||||
|
||||
var boldRegex = /\*\*(.*?)\*\*/g;
|
||||
parsed = parsed.replace(boldRegex, '<strong>$1</strong>');
|
||||
|
||||
var italicRegex = /\*(.*?)\*/g;
|
||||
parsed = parsed.replace(italicRegex, '<em>$1</em>');
|
||||
|
||||
var linkRegex = /\[([^\]]+)]\(([^)]+)\)/g;
|
||||
parsed = parsed.replace(linkRegex, '<a href="$2">$1</a>');
|
||||
|
||||
var breakLineRegex = /\\n/g;
|
||||
parsed = parsed.replace(breakLineRegex, '<br>');
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function removeMarkdown(parsed) {
|
||||
parsed = parsed.replace(/<\/?[^>]+(>|$)/g, '');
|
||||
|
||||
var grayTextRegex = /--(.*?)--/g;
|
||||
parsed = parsed.replace(grayTextRegex, '$1');
|
||||
|
||||
var boldRegex = /\*\*(.*?)\*\*/g;
|
||||
parsed = parsed.replace(boldRegex, '$1');
|
||||
|
||||
var italicRegex = /\*(.*?)\*/g;
|
||||
parsed = parsed.replace(italicRegex, '$1');
|
||||
|
||||
var linkRegex = /\[([^\]]+)]\(([^)]+)\)/g;
|
||||
parsed = parsed.replace(linkRegex, '$1');
|
||||
|
||||
var breakLineRegex = /\\n/g;
|
||||
parsed = parsed.replace(breakLineRegex, '');
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
if (!fs.existsSync(configName + '.json')) {
|
||||
parseAudioDevice((result) => {
|
||||
@@ -285,7 +327,8 @@ app.get('/', (req, res) => {
|
||||
isAdminAuthenticated: req.session.isAdminAuthenticated,
|
||||
isTuneAuthenticated: req.session.isTuneAuthenticated,
|
||||
tunerName: serverConfig.identification.tunerName,
|
||||
tunerDesc: serverConfig.identification.tunerDesc,
|
||||
tunerDesc: parseMarkdown(serverConfig.identification.tunerDesc),
|
||||
tunerDescMeta: removeMarkdown(serverConfig.identification.tunerDesc),
|
||||
tunerLock: serverConfig.lockToAdmin,
|
||||
publicTuner: serverConfig.publicTuner
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fm-dx-webserver",
|
||||
"version": "1.0.8",
|
||||
"version": "1.0.9",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -78,7 +78,7 @@ label {
|
||||
#settings, #back-btn, #users-online-container {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
color: white;
|
||||
color: var(--color-text);
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
@@ -189,7 +189,7 @@ label {
|
||||
#data-pi {
|
||||
font-size: 24px;
|
||||
margin-top: 50px;
|
||||
color: #aaa;
|
||||
color: var(--color-text-2)
|
||||
}
|
||||
h2.show-phone {
|
||||
display: inline;
|
||||
@@ -272,4 +272,12 @@ label {
|
||||
margin-bottom: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
h2.mb-0 {
|
||||
margin-bottom: 0;
|
||||
margin-top: 2px !important;
|
||||
}
|
||||
#af-list ul {
|
||||
max-height: 330px;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ input[type="text"], textarea, input[type="password"] {
|
||||
box-sizing: border-box;
|
||||
border: 2px solid transparent;
|
||||
outline: 0;
|
||||
color: white;
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-1);
|
||||
font-family: 'Titillium Web', sans-serif;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ input[type="text"], textarea, input[type="password"] {
|
||||
box-sizing: border-box;
|
||||
border: 2px solid transparent;
|
||||
outline: 0;
|
||||
color: white;
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-1);
|
||||
font-family: 'Titillium Web', sans-serif;
|
||||
}
|
||||
@@ -112,10 +112,12 @@ input[type="range"]::-moz-range-thumb {
|
||||
box-sizing: border-box;
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
background-color: var(--color-4);
|
||||
border-radius: 0px 30px 30px 0px;
|
||||
border: 0;
|
||||
outline: none;
|
||||
background: url('../images/speaker.svg') center no-repeat, var(--color-5);
|
||||
background-position: center;
|
||||
background-size: 20px;
|
||||
border-radius: 30px;
|
||||
outline: 4px solid var(--color-5);
|
||||
outline-offset: -3px;
|
||||
/* slider progress trick */
|
||||
box-shadow: -420px 0 0 400px var(--color-4);
|
||||
}
|
||||
|
||||
@@ -99,10 +99,14 @@
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.text-color-default {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.text-medium {
|
||||
font-size: 24px;
|
||||
color: #aaa;
|
||||
font-weight: 300;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.text-medium-big {
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
|
||||
:root {
|
||||
--color-main: #111;
|
||||
--color-main-bright: #aaa;
|
||||
--color-main: #000;
|
||||
--color-main-bright: #ccc;
|
||||
--color-text: white;
|
||||
|
||||
--color-1: color-mix(in srgb, var(--color-main) 95%, var(--color-main-bright));
|
||||
--color-2: color-mix(in srgb, var(--color-main) 75%, var(--color-main-bright));
|
||||
--color-3: color-mix(in srgb, var(--color-main) 50%, var(--color-main-bright));
|
||||
--color-4: color-mix(in srgb, var(--color-main) 20%, var(--color-main-bright));
|
||||
--color-5: color-mix(in srgb, var(--color-main) 0%, var(--color-main-bright));
|
||||
--color-1: color-mix(in srgb, var(--color-main) 95%, var(--color-main-bright)); /* 5% Brightness */
|
||||
--color-2: color-mix(in srgb, var(--color-main) 75%, var(--color-main-bright)); /* 25% Brightness */
|
||||
--color-3: color-mix(in srgb, var(--color-main) 50%, var(--color-main-bright)); /* 50% Brightness */
|
||||
--color-4: color-mix(in srgb, var(--color-main) 20%, var(--color-main-bright)); /* 80% Brightness */
|
||||
--color-5: color-mix(in srgb, var(--color-main) 5%, var(--color-main-bright)); /* 95% Brightness */
|
||||
|
||||
--color-text-2: #ccc;
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -41,7 +44,7 @@
|
||||
|
||||
body {
|
||||
font-family: 'Titillium Web', sans-serif;
|
||||
color: white;
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-main);
|
||||
transition: 0.3s ease-in-out background-color;
|
||||
margin: 0 auto;
|
||||
@@ -72,5 +75,9 @@ body {
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
color: var(--color-text-2);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
border-bottom: 1px solid var(--color-4);
|
||||
}
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
|
||||
.close:hover {
|
||||
color: white;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.modal-content .button-close {
|
||||
|
||||
7
web/images/speaker.svg
Normal file
7
web/images/speaker.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.0" width="500" height="500" viewBox="0 0 75 75">
|
||||
<path d="M39.389,13.769 L22.235,28.606 L6,28.606 L6,47.699 L21.989,47.699 L39.389,62.75 L39.389,13.769z"
|
||||
style="stroke:rgba(0,0,0,0);stroke-width:5;stroke-linejoin:round;fill:rgba(0,0,0,0.25);"
|
||||
/>
|
||||
<path d="M48,27.6a19.5,19.5 0 0 1 0,21.4M55.1,20.5a30,30 0 0 1 0,35.6M61.6,14a38.8,38.8 0 0 1 0,48.6" style="fill:none;stroke:rgba(0,0,0,0.25);stroke-width:5;stroke-linecap:round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 541 B |
@@ -12,7 +12,7 @@
|
||||
<meta property="og:title" content="FM-DX WebServer [<%= tunerName %>]">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:image" content="favicon2.png">
|
||||
<meta property="og:description" content="Server description: <%= tunerDesc %>.">
|
||||
<meta property="og:description" content="Server description: <%= tunerDescMeta %>.">
|
||||
|
||||
<script src="js/init.js"></script>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<div class="panel-100 no-bg tuner-info">
|
||||
<h1 id="tuner-name"><%= tunerName %> <% if (!publicTuner) { %><i class="fa-solid fa-key pointer" title="Only people with tune password can tune."></i>
|
||||
<% } else if (tunerLock) { %><i class="fa-solid fa-lock pointer" title="Tuner is currently locked to admin."></i><% } %></h1>
|
||||
<p id="tuner-desc"><%= tunerDesc %></p>
|
||||
<p id="tuner-desc"><%- tunerDesc %></p>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
<div class="canvas-container hide-phone">
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
<div id="flags-container-desktop" class="panel-33">
|
||||
<h2 class="show-phone">
|
||||
<div class="data-pty" style="color:white;"></div>
|
||||
<div class="data-pty text-color-default"></div>
|
||||
</h2>
|
||||
<h3 style="margin-top:0;margin-bottom:0;" class="color-4 flex-center">
|
||||
<span class="data-tp">TP</span>
|
||||
@@ -103,7 +103,7 @@
|
||||
<h2>SIGNAL</h2>
|
||||
<span class="text-big">
|
||||
<span id="data-signal"></span><!--
|
||||
--><span id="data-signal-decimal" class="text-medium-big" style="color: #ccc;"></span>
|
||||
--><span id="data-signal-decimal" class="text-medium-big" style="opacity:0.7;"></span>
|
||||
<span id="signal-units" class="text-medium">dBf</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -154,13 +154,15 @@
|
||||
|
||||
<div class="panel-33 hover-brighten">
|
||||
<div id="data-station-container">
|
||||
<h2 style="margin-top: 4px;">
|
||||
<h2 style="margin-top: 4px;" class="mb-0">
|
||||
<span id="data-station-name"></span>
|
||||
</h2>
|
||||
<h4 class="m-0">
|
||||
<span id="data-station-city"></span>, <span id="data-station-itu"></span>
|
||||
</h4>
|
||||
<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>°
|
||||
<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>°
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,7 +182,7 @@
|
||||
</div>
|
||||
<div id="flags-container-phone" class="panel-33">
|
||||
<h2 class="show-phone">
|
||||
<div class="data-pty" style="color:white;"></div>
|
||||
<div class="data-pty text-color-default"></div>
|
||||
</h2>
|
||||
<h3 style="margin-top:0;margin-bottom:0;" class="color-4 flex-center">
|
||||
<span class="data-tp">TP</span>
|
||||
@@ -216,7 +218,8 @@
|
||||
<li class="option" data-value="theme5">Orange</li>
|
||||
<li class="option" data-value="theme6">Pink</li>
|
||||
<li class="option" data-value="theme7">Blurple</li>
|
||||
<li class="option" data-value="theme8">AMOLED</li>
|
||||
<li class="option" data-value="theme8">Bee</li>
|
||||
<li class="option" data-value="theme9">Retro</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -269,13 +272,8 @@
|
||||
<p class="text-small" id="current-ping"></p>
|
||||
|
||||
<div class="version-info">
|
||||
<p class="text-small">FM-DX WebServer <br>by <a href="https://noobish.eu" target="_blank">Noobish</a> & the OpenRadio community.</p>
|
||||
<span style="color: var(--color-3);">v1.0.8 [19/2/2024]</span>
|
||||
<p class="text-small bottom-50">
|
||||
<span class="text-smaller">librds & maps.fmdx.pl by <a href="https://fmdx.pl" target="_blank">Konrad Kosmatka</a></span><br>
|
||||
<span class="text-smaller">3LAS by <a href="https://github.com/JoJoBond/3LAS" target="_blank">JoJoBond</a></span><br>
|
||||
<span class="text-smaller">flat-flags by <a href="https://github.com/luishdez/flat-flags/tree/master" target="_blank">luishdez</a></span><br>
|
||||
</p>
|
||||
<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>
|
||||
<span style="color: var(--color-3);">v1.0.9 [23/2/2024]</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,23 +39,6 @@ $(document).ready(function () {
|
||||
}
|
||||
});
|
||||
|
||||
var input = $("#tuner-desc").text();
|
||||
var parsed = input;
|
||||
|
||||
var grayTextRegex = /--(.*?)--/g;
|
||||
parsed = parsed.replace(grayTextRegex, '<span class="text-gray">$1</span>');
|
||||
|
||||
var boldRegex = /\*\*(.*?)\*\*/g;
|
||||
parsed = parsed.replace(boldRegex, '<strong>$1</strong>');
|
||||
|
||||
var italicRegex = /\*(.*?)\*/g;
|
||||
parsed = parsed.replace(italicRegex, '<em>$1</em>');
|
||||
|
||||
var breakLineRegex = /\\n/g;
|
||||
parsed = parsed.replace(breakLineRegex, '<br>');
|
||||
|
||||
$("#tuner-desc").html(parsed);
|
||||
|
||||
const textInput = $('#commandinput');
|
||||
|
||||
textInput.on('change', function (event) {
|
||||
@@ -568,7 +551,7 @@ function updateDataElements(parsedData) {
|
||||
parsedData.ps = parsedData.ps.replace(/\s/g, '_');
|
||||
}
|
||||
$('#data-ps').html(parsedData.ps === '?' ? "<span class='opacity-half'>?</span>" : processString(parsedData.ps, parsedData.ps_errors));
|
||||
$('.data-tp').html(parsedData.tp === false ? "<span class='opacity-half'>TP</span>" : "TP");
|
||||
$('.data-tp').html(parsedData.tp === 0 ? "<span class='opacity-half'>TP</span>" : "TP");
|
||||
$('.data-ta').html(parsedData.ta === 0 ? "<span class='opacity-half'>TA</span>" : "TA");
|
||||
$('.data-ms').html(parsedData.ms === 0
|
||||
? "<span class='opacity-half'>M</span><span class='opacity-full'>S</span>"
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
// Themes
|
||||
/**
|
||||
* Themes
|
||||
* @param first color
|
||||
* @param second color
|
||||
* @param text color
|
||||
*/
|
||||
const themes = {
|
||||
theme1: ['#111', '#aaa'],
|
||||
theme2: ['#1f0c0c', '#ff7070'],
|
||||
theme3: ['#121c0c', '#a9ff70'],
|
||||
theme4: ['#0c1c1b', '#68f7ee'],
|
||||
theme5: ['#171106', '#f5b642'],
|
||||
theme6: ['#21091d', '#ed51d3'],
|
||||
theme7: ['#0d0b1a', '#8069fa'],
|
||||
theme8: ['#000', '#888'],
|
||||
};
|
||||
theme1: [ 'rgba(0, 0, 0, 1)', 'rgba(204, 204, 204, 1)', 'rgba(255, 255, 255, 1)' ], // Monochrome (Default)
|
||||
theme2: [ 'rgba(31, 12, 12, 1)', 'rgba(255, 112, 112, 1)', 'rgba(255, 255, 255, 1)' ], // Red
|
||||
theme3: [ 'rgba(18, 28, 12, 1)', 'rgba(169, 255, 112, 1)', 'rgba(255, 255, 255, 1)' ], // Green
|
||||
theme4: [ 'rgba(12, 28, 27, 1)', 'rgba(104, 247, 238, 1)', 'rgba(255, 255, 255, 1)' ], // Cyan
|
||||
theme5: [ 'rgba(23, 17, 6, 1)', 'rgba(245, 182, 66, 1)', 'rgba(255, 255, 255, 1)' ], // Orange
|
||||
theme6: [ 'rgba(33, 9, 29, 1)', 'rgba(237, 81, 211, 1)', 'rgba(255, 255, 255, 1)' ], // Pink
|
||||
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)' ], // Sunny
|
||||
theme9: ['rgba(32, 34, 40, 1)', 'rgba(88, 219, 171, 1)', 'rgba(255, 255, 255, 1)' ] // Retro
|
||||
};
|
||||
|
||||
// Signal Units
|
||||
const signalUnits = {
|
||||
@@ -129,10 +135,21 @@
|
||||
});
|
||||
|
||||
|
||||
function setTheme(themeName) {
|
||||
const themeColors = themes[themeName];
|
||||
if (themeColors) {
|
||||
$(':root').css('--color-main', themeColors[0]);
|
||||
$(':root').css('--color-main-bright', themeColors[1]);
|
||||
}
|
||||
}
|
||||
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]);
|
||||
// Calculating 80% of the opacity
|
||||
const newOpacity = opacity * 0.75;
|
||||
// Constructing the new RGBA string with the adjusted opacity
|
||||
const textColor2 = `rgba(${rgbaComponents[0]}, ${rgbaComponents[1]}, ${rgbaComponents[2]}, ${newOpacity})`;
|
||||
|
||||
$(':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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,10 +85,13 @@
|
||||
<div class="form-group">
|
||||
<label for="audio-quality"><i class="fa-solid fa-wave-square"></i> AUDIO QUALITY:</label>
|
||||
<div class="dropdown" style="width: 300px;">
|
||||
<input id="audio-quality" type="text" name="audio-quality" placeholder="128k (saves bandwidth)" readonly />
|
||||
<input id="audio-quality" type="text" name="audio-quality" placeholder="128k (standard)" readonly />
|
||||
<ul class="options">
|
||||
<li data-value="128k" class="option">128k (saves bandwidth)</li>
|
||||
<li data-value="64k" class="option">64k (lowest quality)</li>
|
||||
<li data-value="96k" class="option">96k (low quality)</li>
|
||||
<li data-value="128k" class="option">128k (standard)</li>
|
||||
<li data-value="192k" class="option">192k (higher quality)</li>
|
||||
<li data-value="256k" class="option">256k (highest quality)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -138,18 +141,20 @@
|
||||
|
||||
<div class="panel-33">
|
||||
<h2>MAINTENANCE</h2>
|
||||
<div class="form-group checkbox">
|
||||
<input type="checkbox" id="tuner-public">
|
||||
<label for="tuner-public">Public tuner</label>
|
||||
</div><br>
|
||||
<div class="form-group checkbox">
|
||||
<input type="checkbox" id="tuner-lock">
|
||||
<label for="tuner-lock">Lock to admin</label>
|
||||
</div><br>
|
||||
<div class="form-group checkbox">
|
||||
<input type="checkbox" id="shutdown-tuner">
|
||||
<label for="shutdown-tuner">Auto-shutdown on empty server</label>
|
||||
</div><br>
|
||||
<div class="text-left top-25 bottom-20" style="padding-left: 40px;">
|
||||
<div class="form-group checkbox">
|
||||
<input type="checkbox" id="tuner-public">
|
||||
<label for="tuner-public">Public tuner</label>
|
||||
</div><br>
|
||||
<div class="form-group checkbox">
|
||||
<input type="checkbox" id="tuner-lock">
|
||||
<label for="tuner-lock">Lock to admin</label>
|
||||
</div><br>
|
||||
<div class="form-group checkbox">
|
||||
<input type="checkbox" id="shutdown-tuner">
|
||||
<label for="shutdown-tuner">Auto-shutdown [XDR Only]</label>
|
||||
</div><br>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="tune-pass">Tune password:</label>
|
||||
<input class="input-text w-150" type="password" name="tune-pass" id="tune-pass">
|
||||
|
||||
Reference in New Issue
Block a user