diff --git a/console.js b/console.js new file mode 100644 index 0000000..181b3d0 --- /dev/null +++ b/console.js @@ -0,0 +1,17 @@ +const { verboseMode } = require('./userconfig'); + +const MESSAGE_PREFIX = { + INFO: "\x1b[32m[INFO]\x1b[0m", + DEBUG: "\x1b[36m[DEBUG]\x1b[0m", + }; + +const logInfo = (...messages) => console.log(MESSAGE_PREFIX.INFO, ...messages); +const logDebug = (...messages) => { + if (verboseMode) { + console.log(MESSAGE_PREFIX.DEBUG, ...messages); + } +}; + +module.exports = { + logInfo, logDebug +} \ No newline at end of file diff --git a/datahandler.js b/datahandler.js index 45c35ec..1a3720c 100644 --- a/datahandler.js +++ b/datahandler.js @@ -1,3 +1,4 @@ +/* Libraries / Imports */ const koffi = require('koffi'); const path = require('path'); const os = require('os'); @@ -5,6 +6,8 @@ const win32 = (os.platform() == "win32"); const unicode_type = (win32 ? 'int16_t' : 'int32_t'); const lib = koffi.load(path.join(__dirname, "librdsparser." + (win32 ? "dll" : "so"))); +var rdsBuffer = []; + koffi.proto('void callback_pi(void *rds, void *user_data)'); koffi.proto('void callback_pty(void *rds, void *user_data)'); koffi.proto('void callback_tp(void *rds, void *user_data)'); @@ -62,21 +65,6 @@ const rdsparser = { country_lookup_iso: lib.func('const char* rdsparser_country_lookup_iso(int country)') } -const decode_unicode = function(string) -{ - let content = rdsparser.string_get_content(string); - let length = rdsparser.string_get_length(string); - let array = koffi.decode(content, koffi.array(unicode_type, length)); - return Buffer.from(array, 'utf-8').toString(); -}; - -const decode_errors = function(string) { - let errors = rdsparser.string_get_errors(string); - let length = rdsparser.string_get_length(string); - let array = koffi.decode(errors, koffi.array('uint8_t', length)); - return Uint8Array.from(array).toString(); -}; - const callbacks = { pi: koffi.register(rds => ( value = rdsparser.get_pi(rds) @@ -178,6 +166,21 @@ rdsparser.register_rt(rds, callbacks.rt); rdsparser.register_ptyn(rds, callbacks.ptyn); rdsparser.register_ct(rds, callbacks.ct); +const decode_unicode = function(string) +{ + let content = rdsparser.string_get_content(string); + let length = rdsparser.string_get_length(string); + let array = koffi.decode(content, koffi.array(unicode_type, length)); + return Buffer.from(array, 'utf-8').toString(); +}; + +const decode_errors = function(string) { + let errors = rdsparser.string_get_errors(string); + let length = rdsparser.string_get_length(string); + let array = koffi.decode(errors, koffi.array('uint8_t', length)); + return Uint8Array.from(array).toString(); +}; + const updateInterval = 75; const clientUpdateIntervals = new Map(); // Store update intervals for each client @@ -197,27 +200,9 @@ var dataToSend = { country_iso: 'UN', users: '', }; - -const initialData = { - pi: '?', - freq: 87.500.toFixed(3), - signal: 0, - st: false, - ps: '', - tp: false, - pty: 0, - af: [], - rt0: '', - rt1: '', - country_name: '', - country_iso: 'UN', - users: '' -}; - +const initialData = { ...dataToSend }; const resetToDefault = dataToSend => Object.assign(dataToSend, initialData); -var rdsBuffer = []; - function handleBuffer() { for (let group of rdsBuffer) { @@ -233,15 +218,13 @@ function handleData(ws, receivedData) { const receivedLines = receivedData.split('\n'); for (const receivedLine of receivedLines) { - switch (true) { case receivedLine.startsWith('P'): modifiedData = receivedLine.slice(1); - if (dataToSend.pi.length > modifiedData.length || dataToSend.pi == '?') { + if (dataToSend.pi.length >= modifiedData.length || dataToSend.pi == '?') { dataToSend.pi = modifiedData; } break; - case receivedLine.startsWith('T'): rdsBuffer = []; resetToDefault(dataToSend); @@ -281,8 +264,8 @@ function handleData(ws, receivedData) { if (rdsBuffer.length > 1000) { rdsBuffer.shift(); } + rdsBuffer.push(modifiedData); - //console.log("\"" + modifiedData + "\","); if (rdsBuffer.length > 1) { handleBuffer(); @@ -293,9 +276,9 @@ function handleData(ws, receivedData) { // Send the updated data to the client const dataToSendJSON = JSON.stringify(dataToSend); - if (currentTime - lastUpdateTime >= updateInterval) { - clientUpdateIntervals.set(ws, currentTime); // Update the last update time for this client - ws.send(dataToSendJSON); + if (currentTime - lastUpdateTime >= updateInterval) { + clientUpdateIntervals.set(ws, currentTime); // Update the last update time for this client + ws.send(dataToSendJSON); } } diff --git a/index.js b/index.js index 7e75ab1..d595eb6 100644 --- a/index.js +++ b/index.js @@ -1,41 +1,34 @@ -// Libraries +/* Libraries / Imports */ const express = require('express'); +const app = express(); const http = require('http'); +const httpServer = http.createServer(app); const WebSocket = require('ws'); +const wss = new WebSocket.Server({ noServer: true }); const path = require('path'); const net = require('net'); +const client = new net.Socket(); const crypto = require('crypto'); const dataHandler = require('./datahandler'); +const consoleCmd = require('./console'); const config = require('./userconfig'); -/* Server settings */ const { webServerHost, webServerPort, webServerName, xdrdServerHost, xdrdServerPort, xdrdPassword, qthLatitude, qthLongitude } = config; - -const infoMsg = "\x1b[32m[INFO]\x1b[0m"; -const debugMsg = "\x1b[36m[DEBUG]\x1b[0m"; +const { logInfo, logDebug } = consoleCmd; let receivedSalt = ''; let receivedPassword = false; let currentUsers = 0; -const wss = new WebSocket.Server({ noServer: true }); - -const app = express(); -const httpServer = http.createServer(app); -/* connection to xdrd */ -const client = new net.Socket(); - /* webSocket handlers */ wss.on('connection', (ws, request) => { const clientIp = request.connection.remoteAddress; currentUsers++; dataHandler.showOnlineUsers(currentUsers); - console.log(infoMsg, `Web client \x1b[32mconnected\x1b[0m (${clientIp}) \x1b[90m[${currentUsers}]`); + consoleCmd.logInfo(`Web client \x1b[32mconnected\x1b[0m (${clientIp}) \x1b[90m[${currentUsers}]`); ws.on('message', (message) => { - if(config.verboseMode === true) { - console.log(debugMsg,'Received message from client:', message.toString()); - } + consoleCmd.logDebug('Received message from client:', message.toString()); newFreq = message.toString() * 1000; client.write("T" + newFreq + '\n'); }); @@ -43,14 +36,14 @@ wss.on('connection', (ws, request) => { ws.on('close', (code, reason) => { currentUsers--; dataHandler.showOnlineUsers(currentUsers); - console.log(infoMsg, `Web client \x1b[31mdisconnected\x1b[0m (${clientIp}) \x1b[90m[${currentUsers}]`); + consoleCmd.logInfo(`Web client \x1b[31mdisconnected\x1b[0m (${clientIp}) \x1b[90m[${currentUsers}]`); }); ws.on('error', console.error); }); -// Serve static files from the "web" folder +/* Serving of HTML files */ app.use(express.static(path.join(__dirname, 'web'))); // Function to authenticate with the xdrd server @@ -68,7 +61,7 @@ function authenticateWithXdrd(client, salt, password) { // WebSocket client connection client.connect(xdrdServerPort, xdrdServerHost, () => { - console.log(infoMsg, 'Connected to xdrd successfully.'); + consoleCmd.logInfo('Connected to xdrd successfully.'); client.once('data', (data) => { const receivedData = data.toString(); @@ -107,10 +100,10 @@ httpServer.on('upgrade', (request, socket, head) => { }); httpServer.listen(webServerPort, webServerHost, () => { - console.log(infoMsg, `Web server is running at \x1b[34mhttp://${webServerHost}:${webServerPort}\x1b[0m.`); + consoleCmd.logInfo(`Web server is running at \x1b[34mhttp://${webServerHost}:${webServerPort}\x1b[0m.`); }); - +/* Static data are being sent through here on connection - these don't change when the server is running */ app.get('/static_data', (req, res) => { res.json({ qthLatitude, qthLongitude, webServerName }); }); \ No newline at end of file diff --git a/userconfig.js b/userconfig.js index 415e3ac..236afd1 100644 --- a/userconfig.js +++ b/userconfig.js @@ -9,7 +9,7 @@ const xdrdPassword = 'changememe'; // xdrd password (optional) const qthLatitude = '50.357935'; // your latitude, useful for maps.fmdx.pl integration const qthLongitude = '15.924395'; // your longitude, useful for maps.fmdx.pl integration -const verboseMode = false; // if true, console will display extra messages +const verboseMode = true; // if true, console will display extra messages // DO NOT MODIFY ANYTHING BELOW THIS LINE module.exports = { diff --git a/web/css/breadcrumbs.css b/web/css/breadcrumbs.css new file mode 100644 index 0000000..f18de39 --- /dev/null +++ b/web/css/breadcrumbs.css @@ -0,0 +1,47 @@ +h2 { + color: var(--color-4); + margin-bottom: 0; +} + +h3 { + font-size: 22px; +} + +#data-ps, #data-rt0, #data-rt1 { + font-family: monospace; +} + +#color-settings, #settings { + background: transparent; + border: 0; + color: white; + position: absolute; + top: 15px; + right: 15px; + font-size: 16px; + width: 64px; + height: 64px; + line-height: 64px; + text-align: center; + border-radius: 50%; + transition: 500ms ease-in-out background; + cursor: pointer; +} + +#color-settings { + top: 96px; +} + +#settings:hover, #color-settings:hover { + background: var(--color-3); +} + +#af-list ul { + display:list-item; + padding: 0; + list-style-type: none; + height: 425px; + overflow-y: scroll; + overflow-x: hidden; + margin-bottom: 0; +} \ No newline at end of file diff --git a/web/css/buttons.css b/web/css/buttons.css new file mode 100644 index 0000000..56ba241 --- /dev/null +++ b/web/css/buttons.css @@ -0,0 +1,241 @@ + +#tune-buttons input[type="text"] { + width: 50%; + height: 100%; + min-height: 46px; + padding-left: 20px; + box-sizing: border-box; + border: 2px solid transparent; + outline: 0; + color: white; + background-color: var(--color-1); + font-family: 'Titillium Web', sans-serif; + } + + input[type="text"]:hover { + border: 2px solid var(--color-main-bright); + } + + #tune-buttons button { + box-sizing: border-box; + background-color: var(--color-4); + border: 0; + color: var(--color-1); + width: 25%; + height: 100%; + display: block; + padding: 14px; + cursor: pointer; + transition: background-color 0.3s ease-in-out; + } + + #tune-buttons button:hover { + background-color: var(--color-main-bright); + } + + #freq-down { + border-radius: 30px 0 0 30px; + } + + #freq-up { + border-radius: 0 30px 30px 0; + } + +input[type="range"] { + margin: 0; + /* removing default appearance */ + -webkit-appearance: none; + appearance: none; + /* creating a custom design */ + width: 100%; + cursor: pointer; + outline: none; + /* slider progress trick */ + overflow: hidden; + border-radius: 30px; + height: 100%; + background: transparent; +} + +/* Track: Mozilla Firefox */ +input[type="range"]::-moz-range-track { + height: 48px; + background: var(--color-1); + border-radius: 30px; + border: 0; +} + +/* Thumb: webkit */ +input[type="range"]::-webkit-slider-thumb { + /* removing default appearance */ + -webkit-appearance: none; + appearance: none; + /* creating a custom design */ + height: 48px; + width: 48px; + background-color: #fff; + border-radius: 10px; + border: 2px solid var(--color-4); + /* slider progress trick */ + box-shadow: -407px 0 0 400px var(--color-4); +} + +/* Thumb: Firefox */ +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; + /* slider progress trick */ + box-shadow: -420px 0 0 400px var(--color-4); +} + +/* Toggle Switch */ + +.toggleSwitch span span { + display: none; +} + +.toggleSwitch { + user-select: none; + display: inline-block; + height: 48px; + position: relative; + overflow: hidden; + padding: 0; + cursor: pointer; + width: 100%; + border-radius: 25px; + font-weight: bold; +} +.toggleSwitch * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.toggleSwitch input:focus ~ a, +.toggleSwitch input:focus + label { + outline: none; +} +.toggleSwitch label { + position: relative; + z-index: 3; + display: block; + width: 100%; +} +.toggleSwitch input { + position: absolute; + opacity: 0; + z-index: 5; +} +.toggleSwitch > span { + position: absolute; + left: 0; + width: calc(100% - 6px); + margin: 0; + text-align: left; + white-space: nowrap; + margin:0; +} +.toggleSwitch > span span { + position: absolute; + top: 0; + left: 0; + z-index: 5; + display: block; + width: 50%; + margin-left: 50px; + text-align: left; + font-size: 0.9em; + width: auto; + opacity: 1; + width: 40%; + text-align: center; + line-height:48px; +} +.toggleSwitch a { + position: absolute; + right: 50%; + z-index: 4; + display: block; + top: 0; + bottom: 0; + padding: 0; + left: 0; + width: 50%; + background-color: var(--color-4); + border-radius: 25px; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.toggleSwitch > span span:first-of-type { + color: var(--color-1); + opacity: 1; + left: 0; + margin: 0; + width: 50%; +} +.toggleSwitch > span span:last-of-type { + left:auto; + right:0; + color: var(--color-4); + margin: 0; + width: 50%; +} +.toggleSwitch > span:before { + content: ''; + display: block; + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: -2px; + border-radius: 30px; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; +} +.toggleSwitch input:checked ~ a { + left: calc(50% - 3px); +} + +.toggleSwitch input:checked ~ span span:first-of-type { + left:0; + color: var(--color-4); +} +.toggleSwitch input:checked ~ span span:last-of-type { + color: var(--color-1); +} + +/* End Toggle Switch */ + +select { + height: 42px; + width: 150px; + padding: 10px; + background: var(--color-4); + color: var(--color-1); + border: 0; + border-bottom: 4px solid var(--color-2); + cursor: pointer; + transition: 0.35s ease-in-out background; + font-family: inherit; + font-weight: bold; +} + +select option { + font-family: 'Titillium Web', sans-serif; + font-weight: 300; + padding: 10px; + border: 0; +} + +select:hover { + background: var(--color-5); +} diff --git a/web/css/entry.css b/web/css/entry.css new file mode 100644 index 0000000..5a460ec --- /dev/null +++ b/web/css/entry.css @@ -0,0 +1,7 @@ +@import url('https://fonts.googleapis.com/css2?family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap'); +@import url("main.css"); /* Root stuff that affects the entire webpage (body, wrapper etc.) */ +@import url("breadcrumbs.css"); /* Stuff that applies to random elements only once/twice */ +@import url("buttons.css"); /* Buttons, inputs, select boxes, checkboxes... */ +@import url("helpers.css"); /* Stuff that is used often such as text changers etc */ +@import url("panels.css"); /* Different panels and their sizes */ +@import url("modal.css"); /* Modal window */ \ No newline at end of file diff --git a/web/css/helpers.css b/web/css/helpers.css new file mode 100644 index 0000000..8884eb6 --- /dev/null +++ b/web/css/helpers.css @@ -0,0 +1,89 @@ +.auto { + margin: auto; +} + +.bg-dark { + background: #100d1f; +} + +.bg-none { + background: transparent !important; +} + +.color-1 { + color: var(--color-1); +} + +.color-2 { + color: var(--color-2); +} + +.color-3 { + color: var(--color-3); +} + +.color-4 { + color: var(--color-4); +} + +.flex-container { + display: flex; +} + +.flex-center { + display: flex; + justify-content: center; + align-items: center; +} + +.hover-brighten:hover { + cursor: pointer; + background-color: var(--color-2); +} + +.text-big { + font-size: 60px; + font-weight: 300; +} + +.text-medium { + font-size: 24px; + color: #aaa; + font-weight: 300; +} + +.text-medium-big { + font-size: 46px; +} + +.text-small { + font-size: 13px; +} + +.text-gray { + color: #666; +} + +.text-uppercase { + text-transform: uppercase; +} + +@media only screen and (max-width: 768px) { + .flex-container { + display: block; + } + .flex-phone { + display: flex; + } + .text-medium-big { + font-size: 32px; + } + .text-big { + font-size: 40px; + display: block; + margin-top: -25px; + } + .text-big#data-ps { + margin: 0; + } +} \ No newline at end of file diff --git a/web/css/main.css b/web/css/main.css new file mode 100644 index 0000000..6dc6808 --- /dev/null +++ b/web/css/main.css @@ -0,0 +1,50 @@ + +:root { + --color-main: #111; + --color-main-bright: #aaa; + + --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)); +} + +* { + box-sizing: border-box; +} + +::selection { + background: var(--color-main-bright); + color: inherit; +} + +body { + font-family: 'Titillium Web', sans-serif; + color: white; + background-color: var(--color-main); + transition: 0.3s ease-in-out background-color; +} + +#wrapper { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: auto; + max-width: 1240px; +} + + +@media (max-width: 960px) { + #wrapper { + position: static; + transform: none; + margin: 0 auto; + } +} + +a { + text-decoration: none; + color: white; +} \ No newline at end of file diff --git a/web/css/modal.css b/web/css/modal.css new file mode 100644 index 0000000..6f718a6 --- /dev/null +++ b/web/css/modal.css @@ -0,0 +1,87 @@ +.modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.6); /* Semi-transparent background */ + opacity: 0; + transition: opacity 0.3s ease-in-out; /* Fade-in/out transition */ + z-index: 20; /* Ensure the modal is above other content */ + color: var(--color-4); + backdrop-filter: blur(10px); +} + +/* Style for the modal content */ +.modal-content { + box-sizing: border-box; + position: absolute; + top: 50vh; + left: 50vw; + transform: translate(-50%, -50%); + background-color: var(--color-main); + padding: 30px; + border-radius: 30px; + 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 */ + min-width: 500px; +} + +.modal-content p { + margin: 0; +} + +.modal-title { + font-size: 20px; + position: absolute; + font-weight: 300; + top: 14px; + left: 30px; +} + +/* Style for the close button */ +.close { + position: absolute; + top: 17px; + right: 30px; + cursor: pointer; + transition: 0.3s ease-in-out color; +} + +.close:hover { + color: white; +} + +.modal-content .button-close { + position: absolute; + bottom: 25px; + right: 35px; + width: 100px; + height: 48px; + border-radius: 30px; + background: var(--color-4); + font-weight: bold; + border: 0; + transition: 0.35s ease-in-out background; + cursor: pointer; +} + +.modal-content .button-close:hover { + background: var(--color-5); +} + +.modal label { + font-size: 12px; + font-weight: bold; + text-transform: uppercase; + display: block; +} + +@media only screen and (max-width: 768px) { + .modal-content { + min-width: 90% !important; + margin: auto; + } +} \ No newline at end of file diff --git a/web/css/panels.css b/web/css/panels.css new file mode 100644 index 0000000..e493ad2 --- /dev/null +++ b/web/css/panels.css @@ -0,0 +1,77 @@ +.panel-10 { + width: 10%; + background: var(--color-1); + margin-left: 10px; + margin-right: 10px; + border-radius: 30px; + text-align: center; + margin-top: 30px; + margin-bottom: 30px; +} + +.panel-33 { + width: 33%; + background-color: var(--color-1); + margin-left: 10px; + margin-right: 10px; + border-radius: 30px; + text-align: center; + margin-top: 30px; + transition: 0.3s ease-in-out background-color; +} + +.panel-75 { + width: 68%; + background: var(--color-1); + margin-left: 10px; + margin-right: 10px; + border-radius: 30px; + text-align: center; + margin-top: 30px; + transition: 0.3s ease-in-out background-color; +} + +.panel-90 { + width: 88%; + background: var(--color-1); + margin-left: 10px; + margin-right: 10px; + border-radius: 30px; + text-align: center; + margin-top: 30px; +} + + +.panel-100 { + width: 98%; + background: var(--color-1); + margin-left: 10px; + margin-right: 10px; + min-height: 100px; + border-radius: 30px; + text-align: center; + margin-top: 30px; +} + + + +@media only screen and (max-width: 768px) { + .panel-10, .panel-33, .panel-90 { + width: 90%; + margin: auto; + margin-bottom: 20px; + } + .panel-75 { + margin: 80px auto 0 auto !important; + width: 90%; + } + .panel-33 h2 { + padding: 20px; + padding-top: 5px; + } + .panel-100 { + width: 90%; + margin: auto; + } + +} \ No newline at end of file diff --git a/web/css/styles.css b/web/css/styles.css deleted file mode 100644 index 5704fd2..0000000 --- a/web/css/styles.css +++ /dev/null @@ -1,586 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap'); - -:root { - --color-main: #111; - --color-main-bright: #aaa; - - --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: var(--color-1); -} - -.color-2 { - color: var(--color-2); -} - -.color-3 { - color: var(--color-3); -} - -.color-4 { - color: var(--color-4); -} - -::selection { - background: var(--color-main-bright); - color: inherit; -} - -body { - font-family: 'Titillium Web', sans-serif; - color: white; - background-color: var(--color-main); - transition: 0.3s ease-in-out background-color; -} - -a { - text-decoration: none; - color: white; -} - -#data-pi { - text-transform: uppercase; -} - -#wrapper { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: auto; - max-width: 1240px; -} - -#color-settings, #settings { - background: transparent; - border: 0; - color: white; - position: absolute; - top: 15px; - right: 15px; - font-size: 16px; - width: 64px; - height: 64px; - line-height: 64px; - text-align: center; - border-radius: 50%; - transition: 500ms ease-in-out background; - cursor: pointer; -} - -#color-settings { - top: 96px; -} - -#settings:hover, #color-settings:hover { - background: var(--color-3); -} - -h2 { - color: var(--color-4); - margin-bottom: 0; -} - -h3 { - font-size: 22px; -} - -.flex-container { - display: flex; -} - -.flex-center { - display: flex; - justify-content: center; - align-items: center; -} - -.no-bg { - background: transparent !important; -} - -.panel-10 { - width: 10%; - background: var(--color-1); - margin-left: 10px; - margin-right: 10px; - border-radius: 30px; - text-align: center; - margin-top: 30px; - margin-bottom: 30px; -} - -.panel-33 { - width: 33%; - background-color: var(--color-1); - margin-left: 10px; - margin-right: 10px; - border-radius: 30px; - text-align: center; - margin-top: 30px; - transition: 0.3s ease-in-out background-color; -} - -.hover-brighten:hover { - cursor: pointer; - background-color: var(--color-2); -} - -.panel-75 { - width: 68%; - background: var(--color-1); - margin-left: 10px; - margin-right: 10px; - border-radius: 30px; - text-align: center; - margin-top: 30px; - transition: 0.3s ease-in-out background-color; -} - -.panel-90 { - width: 88%; - background: var(--color-1); - margin-left: 10px; - margin-right: 10px; - border-radius: 30px; - text-align: center; - margin-top: 30px; -} - - -.panel-100 { - width: 98%; - background: var(--color-1); - margin-left: 10px; - margin-right: 10px; - min-height: 100px; - border-radius: 30px; - text-align: center; - margin-top: 30px; -} - -#af-list ul { - display:list-item; - padding: 0; - list-style-type: none; - height: 425px; - overflow-y: scroll; - overflow-x: hidden; - margin-bottom: 0; -} - -.auto { - margin: auto; -} - -.text-big { - font-size: 60px; - font-weight: 300; -} - -.text-medium { - font-size: 24px; - color: #aaa; - font-weight: 300; -} - -.text-medium-big { - font-size: 46px; -} - -.text-small { - font-size: 13px; -} - -.text-gray { - color: #666; -} - -.bg-dark { - background: #100d1f; -} - -#tune-buttons input[type="text"] { - width: 50%; - height: 100%; - min-height: 46px; - padding-left: 20px; - box-sizing: border-box; - border: 2px solid transparent; - outline: 0; - color: white; - background-color: var(--color-1); - font-family: 'Titillium Web', sans-serif; -} - -input[type="text"]:hover { - border: 2px solid var(--color-main-bright); -} - -#tune-buttons button { - box-sizing: border-box; - background-color: var(--color-4); - border: 0; - color: var(--color-1); - width: 25%; - height: 100%; - display: block; - padding: 14px; - cursor: pointer; - transition: background-color 0.3s ease-in-out; -} - -#tune-buttons button:hover { - background-color: var(--color-main-bright); -} - -#freq-down { - border-radius: 30px 0 0 30px; -} - -#freq-up { - border-radius: 0 30px 30px 0; -} - -@media only screen and (max-width: 768px) { - .flex-container { - display: block; - } - .flex-phone { - display: flex; - } - .modal-content { - min-width: 90% !important; - margin: auto; - } - .panel-10, .panel-33, .panel-90 { - width: 90%; - margin: auto; - margin-bottom: 20px; - } - .panel-75 { - margin: 80px auto 0 auto !important; - width: 90%; - } - .panel-33 h2 { - padding: 20px; - padding-top: 5px; - } - .text-medium-big { - font-size: 32px; - } - .text-big { - font-size: 40px; - display: block; - margin-top: -25px; - } - .text-big#data-ps { - margin: 0; - } - .panel-100 { - width: 90%; - margin: auto; - } - -} - -@media (max-width: 960px) { - #wrapper { - position: static; - transform: none; - margin: 0 auto; - } -} - -input[type="range"] { - margin: 0; - /* removing default appearance */ - -webkit-appearance: none; - appearance: none; - /* creating a custom design */ - width: 100%; - cursor: pointer; - outline: none; - /* slider progress trick */ - overflow: hidden; - border-radius: 30px; - height: 100%; - background: transparent; -} - -/* Track: Mozilla Firefox */ -input[type="range"]::-moz-range-track { - height: 48px; - background: var(--color-1); - border-radius: 30px; - border: 0; -} - -/* Thumb: webkit */ -input[type="range"]::-webkit-slider-thumb { - /* removing default appearance */ - -webkit-appearance: none; - appearance: none; - /* creating a custom design */ - height: 48px; - width: 48px; - background-color: #fff; - border-radius: 10px; - border: 2px solid var(--color-4); - /* slider progress trick */ - box-shadow: -407px 0 0 400px var(--color-4); -} - -/* Thumb: Firefox */ -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; - /* slider progress trick */ - box-shadow: -420px 0 0 400px var(--color-4); -} - -/* Toggle Switch */ - -.toggleSwitch span span { - display: none; -} - -.toggleSwitch { - user-select: none; - display: inline-block; - height: 48px; - position: relative; - overflow: hidden; - padding: 0; - cursor: pointer; - width: 100%; - border-radius: 25px; - font-weight: bold; -} -.toggleSwitch * { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -.toggleSwitch input:focus ~ a, -.toggleSwitch input:focus + label { - outline: none; -} -.toggleSwitch label { - position: relative; - z-index: 3; - display: block; - width: 100%; -} -.toggleSwitch input { - position: absolute; - opacity: 0; - z-index: 5; -} -.toggleSwitch > span { - position: absolute; - left: 0; - width: calc(100% - 6px); - margin: 0; - text-align: left; - white-space: nowrap; - margin:0; -} -.toggleSwitch > span span { - position: absolute; - top: 0; - left: 0; - z-index: 5; - display: block; - width: 50%; - margin-left: 50px; - text-align: left; - font-size: 0.9em; - width: auto; - opacity: 1; - width: 40%; - text-align: center; - line-height:48px; -} -.toggleSwitch a { - position: absolute; - right: 50%; - z-index: 4; - display: block; - top: 0; - bottom: 0; - padding: 0; - left: 0; - width: 50%; - background-color: var(--color-4); - border-radius: 25px; - -webkit-transition: all 0.2s ease-out; - -moz-transition: all 0.2s ease-out; - transition: all 0.2s ease-out; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -} -.toggleSwitch > span span:first-of-type { - color: var(--color-1); - opacity: 1; - left: 0; - margin: 0; - width: 50%; -} -.toggleSwitch > span span:last-of-type { - left:auto; - right:0; - color: var(--color-4); - margin: 0; - width: 50%; -} -.toggleSwitch > span:before { - content: ''; - display: block; - width: 100%; - height: 100%; - position: absolute; - left: 0; - top: -2px; - border-radius: 30px; - -webkit-transition: all 0.2s ease-out; - -moz-transition: all 0.2s ease-out; - transition: all 0.2s ease-out; -} -.toggleSwitch input:checked ~ a { - left: calc(50% - 3px); -} - -.toggleSwitch input:checked ~ span span:first-of-type { - left:0; - color: var(--color-4); -} -.toggleSwitch input:checked ~ span span:last-of-type { - color: var(--color-1); -} - -/* End Toggle Switch */ - - - -/* Style for the modal container */ -.modal { - display: none; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.6); /* Semi-transparent background */ - opacity: 0; - transition: opacity 0.3s ease-in-out; /* Fade-in/out transition */ - z-index: 20; /* Ensure the modal is above other content */ - color: var(--color-4); - backdrop-filter: blur(10px); -} - -/* Style for the modal content */ -.modal-content { - box-sizing: border-box; - position: absolute; - top: 50vh; - left: 50vw; - transform: translate(-50%, -50%); - background-color: var(--color-main); - padding: 30px; - border-radius: 30px; - 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 */ - min-width: 500px; -} - -.modal-content p { - margin: 0; -} - -.modal-title { - font-size: 20px; - position: absolute; - font-weight: 300; - top: 14px; - left: 30px; -} - -/* Style for the close button */ -.close { - position: absolute; - top: 17px; - right: 30px; - cursor: pointer; - transition: 0.3s ease-in-out color; -} - -.close:hover { - color: white; -} - -.modal-content .button-close { - position: absolute; - bottom: 25px; - right: 35px; - width: 100px; - height: 48px; - border-radius: 30px; - background: var(--color-4); - font-weight: bold; - border: 0; - transition: 0.35s ease-in-out background; - cursor: pointer; -} - -.modal-content .button-close:hover { - background: var(--color-5); -} - -.modal label { - font-size: 12px; - font-weight: bold; - text-transform: uppercase; - display: block; -} - -select { - height: 42px; - width: 150px; - padding: 10px; - background: var(--color-4); - color: var(--color-1); - border: 0; - border-bottom: 4px solid var(--color-2); - cursor: pointer; - transition: 0.35s ease-in-out background; - font-family: inherit; - font-weight: bold; -} - -select option { - font-family: 'Titillium Web', sans-serif; - font-weight: 300; - padding: 10px; - border: 0; -} - -select:hover { - background: var(--color-5); -} - -#data-ps, #data-rt0, #data-rt1 { - font-family: monospace; -} diff --git a/web/index.html b/web/index.html index cbe2748..9c1e616 100644 --- a/web/index.html +++ b/web/index.html @@ -2,7 +2,7 @@