This commit is contained in:
naielv
2025-08-04 19:59:25 +02:00
parent 1ee951fc9f
commit 0fcd6ccaba
8 changed files with 455 additions and 365 deletions

BIN
assets/load.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -1,306 +1,307 @@
html {
html { color-scheme: light only;
color-scheme: light only;
}
body {
font-family: Arial, Helvetica, sans-serif;
}
main {
/*max-width: 45rem;
margin: 0 auto;*/
padding: 0 15px;
}
.supermesh-indicator {
border-top-left-radius: 15px;
background-color: greenyellow;
border-top: 5px solid green;
border-left: 5px solid green;
padding: 15px;
max-width: 30rem;
position: fixed;
right: 0;
bottom: 0;
color: black;
display: none;
}
.supermesh-indicator a {
color: blue;
}
details.supermesh-indicator summary {
font-size: unset;
}
.link,
a {
color: blue;
text-decoration: underline;
cursor: pointer;
}
.link:hover,
a:hover {
text-decoration: underline;
}
#articleID {
font-family: monospace;
}
@media (prefers-color-scheme: dark) {
.link,
a {
color: lightblue;
}
}
@media print {
.supermesh-indicator,
.no_print {
display: none;
}
}
main {
margin-bottom: 25rem;
}
button,
.button {
display: inline-block;
padding: 5px 10px;
background-color: beige;
border: 2px solid black;
font-size: 20px;
margin: 3px;
text-decoration: none;
color: black;
}
button:hover,
.button:hover {
text-decoration: underline;
}
/* https://coolors.co/palette/ff0000-ff8700-ffd300-deff0a-a1ff0a-0aff99-0aefff-147df5-580aff-be0aff */
.rojo {
background: #ff0000;
color: white;
}
.btn1 {
background: #ff0000;
color: white;
}
.btn2 {
background: #ff8700;
color: white;
}
.btn3 {
background: #ffd300;
color: black;
}
.btn4 {
background: #deff0a;
color: black;
}
.btn5 {
background: #a1ff0a;
color: black;
}
.btn6 {
background: #0aff99;
color: black;
}
.btn7 {
background: #0aefff;
color: black;
}
.btn8 {
background: #147df5;
color: white;
}
.nav-disabled {
background: black !important;
color: grey !important;
}
.nav-disabled:hover {
text-decoration: unset !important;
}
input,
select,
textarea {
font-size: 18px;
padding: 5px;
width: calc(100% - 11px);
}
select {
width: 100%;
}
details input,
details select,
details textarea {
font-size: 18px;
padding: 5px;
width: calc(100% - 15px);
}
input[type="color"] {
width: 50px;
height: 50px;
}
textarea {
height: 150px;
}
details summary {
font-size: 20px;
}
thead tr {
background-color: black;
color: white;
}
table {
display: block;
line-break: loose;
width: fit-content;
min-width: 750px;
border: 1px solid black;
}
table tr th {
line-break: auto;
}
table tr td {
border-bottom: 3px solid black !important;
padding: 5px;
}
.scase {
text-transform: lowercase;
}
.scase:first-letter {
text-transform: uppercase;
}
table tr:hover td {
text-decoration: underline;
background: rgba(200, 200, 200, 0.5);
/* color: black; */
}
table tr:hover td.TextBorder {
background: inherit;
color: inherit;
text-decoration: none;
}
fieldset {
max-width: 25rem;
}
.TextBorder {
color: black;
text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff,
1px 1px 0 #fff;
-webkit-text-stroke: 0.25px #fff;
}
code {
font-size: x-small;
color: gray;
}
.activeSCButton {
border: 7px dashed beige;
color: beige;
background: black !important;
}
.btn1.activeSCButton {
border-color: #ff0000;
color: #ff0000;
}
.btn2.activeSCButton {
border-color: #ff8700;
color: #ff8700;
}
.btn3.activeSCButton {
border-color: #ffd300;
color: #ffd300;
}
.btn4.activeSCButton {
border-color: #deff0a;
color: #deff0a;
}
.btn5.activeSCButton {
border-color: #a1ff0a;
color: #a1ff0a;
}
.btn6.activeSCButton {
border-color: #0aff99;
color: #0aff99;
}
.btn7.activeSCButton {
border-color: #0aefff;
color: #0aefff;
}
.btn8.activeSCButton {
border-color: #147df5;
color: #147df5;
}
hr {
border-color: black;
border-style: solid;
}
#snackbar {
visibility: hidden;
/* min-width: 250px; */
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 1;
right: 70px;
bottom: 25px;
}
#snackbar a {
color: lightblue;
}
#snackbar.show {
visibility: visible;
} }
body {
font-family: Arial, Helvetica, sans-serif;
}
main {
/*max-width: 45rem;
margin: 0 auto;*/
padding: 0 15px;
}
.supermesh-indicator {
border-top-left-radius: 15px;
background-color: greenyellow;
border-top: 5px solid green;
border-left: 5px solid green;
padding: 15px;
max-width: 30rem;
position: fixed;
right: 0;
bottom: 0;
color: black;
display: none;
}
.supermesh-indicator a {
color: blue;
}
details.supermesh-indicator summary {
font-size: unset;
}
.link,
a {
color: blue;
text-decoration: underline;
cursor: pointer;
}
.link:hover,
a:hover {
text-decoration: underline;
}
#articleID {
font-family: monospace;
}
@media (prefers-color-scheme: dark) {
.link,
a {
color: lightblue;
}
}
@media print {
.supermesh-indicator,
.no_print {
display: none;
}
}
main {
margin-bottom: 25rem;
}
button,
.button {
display: inline-block;
padding: 5px 10px;
background-color: beige;
border: 2px solid black;
font-size: 20px;
margin: 3px;
text-decoration: none;
color: black;
}
button:hover,
.button:hover {
text-decoration: underline;
}
/* https://coolors.co/palette/ff0000-ff8700-ffd300-deff0a-a1ff0a-0aff99-0aefff-147df5-580aff-be0aff */
.rojo {
background: #ff0000;
color: white;
}
.btn1 {
background: #ff0000;
color: white;
}
.btn2 {
background: #ff8700;
color: white;
}
.btn3 {
background: #ffd300;
color: black;
}
.btn4 {
background: #deff0a;
color: black;
}
.btn5 {
background: #a1ff0a;
color: black;
}
.btn6 {
background: #0aff99;
color: black;
}
.btn7 {
background: #0aefff;
color: black;
}
.btn8 {
background: #147df5;
color: white;
}
.nav-disabled {
background: black !important;
color: grey !important;
}
.nav-disabled:hover {
text-decoration: unset !important;
}
input,
select,
textarea {
font-size: 18px;
padding: 5px;
width: calc(100% - 11px);
}
select {
width: 100%;
}
details input,
details select,
details textarea {
font-size: 18px;
padding: 5px;
width: calc(100% - 15px);
}
input[type="color"] {
width: 50px;
height: 50px;
}
textarea {
height: 150px;
}
details summary {
font-size: 20px;
}
thead tr {
background-color: black;
color: white;
}
table {
display: block;
line-break: loose;
width: fit-content;
min-width: 750px;
border: 1px solid black;
}
table tr th {
line-break: auto;
}
table tr td {
border-bottom: 3px solid black !important;
padding: 5px;
}
.scase {
text-transform: lowercase;
}
.scase:first-letter {
text-transform: uppercase;
}
table tr:hover td {
text-decoration: underline;
background: rgba(200, 200, 200, 0.5);
/* color: black; */
}
table tr:hover td.TextBorder {
background: inherit;
color: inherit;
text-decoration: none;
}
fieldset {
max-width: 25rem;
}
.TextBorder {
color: black;
text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff,
1px 1px 0 #fff;
-webkit-text-stroke: 0.25px #fff;
}
code {
font-size: x-small;
color: gray;
}
.activeSCButton {
border: 7px dashed beige;
color: beige;
background: black !important;
}
.btn1.activeSCButton {
border-color: #ff0000;
color: #ff0000;
}
.btn2.activeSCButton {
border-color: #ff8700;
color: #ff8700;
}
.btn3.activeSCButton {
border-color: #ffd300;
color: #ffd300;
}
.btn4.activeSCButton {
border-color: #deff0a;
color: #deff0a;
}
.btn5.activeSCButton {
border-color: #a1ff0a;
color: #a1ff0a;
}
.btn6.activeSCButton {
border-color: #0aff99;
color: #0aff99;
}
.btn7.activeSCButton {
border-color: #0aefff;
color: #0aefff;
}
.btn8.activeSCButton {
border-color: #147df5;
color: #147df5;
}
hr {
border-color: black;
border-style: solid;
}
#snackbar {
visibility: hidden;
/* min-width: 250px; */
background-color: #333;
color: #fff;
text-align: center;
border-radius: 2px;
padding: 16px;
position: fixed;
z-index: 1;
right: 70px;
bottom: 25px;
}
#snackbar a {
color: lightblue;
}
#snackbar.show {
visibility: visible;
}

View File

@@ -628,7 +628,7 @@ function TS_IndexElement(
container, container,
rowCallback = undefined, rowCallback = undefined,
canAddCallback = undefined, canAddCallback = undefined,
globalSearchBar = true, globalSearchBar = true
) { ) {
// Every item in config should have: // Every item in config should have:
// key: string // key: string
@@ -639,14 +639,18 @@ function TS_IndexElement(
var tablehead = safeuuid(); var tablehead = safeuuid();
var scrolltable = safeuuid(); var scrolltable = safeuuid();
var searchKeyInput = safeuuid(); var searchKeyInput = safeuuid();
// Create the container with search bar and table // Create the container with search bar and table
container.innerHTML = ` container.innerHTML = `
<div id="${scrolltable}"> <div id="${scrolltable}">
<input type="text" id="${searchKeyInput}" placeholder="🔍 Buscar..." style="width: 100%; max-width: 20rem; padding: 8px; border: 1px solid #ccc; border-radius: 4px; background-color: rebeccapurple; color: white;">
<table> <table>
<thead> <thead>
<tr id="${tablehead}"></tr> <tr style="background: transparent;">
<th colspan="100%" style="padding: 0; background: transparent;">
<input type="text" id="${searchKeyInput}" placeholder="🔍 Buscar..." style="width: calc(100% - 18px); padding: 8px; border: 1px solid #ccc; border-radius: 4px; background-color: rebeccapurple; color: white;">
</th>
</tr>
<tr id="${tablehead}"></tr>
</thead> </thead>
<tbody id="${tablebody}"> <tbody id="${tablebody}">
</tbody> </tbody>
@@ -662,14 +666,17 @@ function TS_IndexElement(
}); });
// Add search functionality // Add search functionality
const searchKeyEl = document.getElementById(searchKeyInput); const searchKeyEl = document.getElementById(searchKeyInput);
searchKeyEl.addEventListener('input', debounce(() => render(), 300)); searchKeyEl.addEventListener(
"input",
debounce(() => render(), 300)
);
function searchInData(data, searchValue, config) { function searchInData(data, searchValue, config) {
if (!searchValue) return true; if (!searchValue) return true;
// Search in ID // Search in ID
if (data._key.toLowerCase().includes(searchValue)) return true; if (data._key.toLowerCase().includes(searchValue)) return true;
// Search in configured fields // Search in configured fields
for (const field of config) { for (const field of config) {
const value = data[field.key]; const value = data[field.key];
@@ -681,9 +688,12 @@ function TS_IndexElement(
try { try {
const comandaData = JSON.parse(data.Comanda); const comandaData = JSON.parse(data.Comanda);
// Search in all comanda fields // Search in all comanda fields
if (Object.values(comandaData).some(v => if (
String(v).toLowerCase().includes(searchValue) Object.values(comandaData).some((v) =>
)) return true; String(v).toLowerCase().includes(searchValue)
)
)
return true;
} catch (e) { } catch (e) {
// If JSON parse fails, search in raw string // If JSON parse fails, search in raw string
if (data.Comanda.toLowerCase().includes(searchValue)) return true; if (data.Comanda.toLowerCase().includes(searchValue)) return true;
@@ -693,8 +703,10 @@ function TS_IndexElement(
const persona = SC_Personas[value]; const persona = SC_Personas[value];
if (persona) { if (persona) {
// Search in persona fields // Search in persona fields
if (persona.Nombre?.toLowerCase().includes(searchValue)) return true; if (persona.Nombre?.toLowerCase().includes(searchValue))
if (persona.Region?.toLowerCase().includes(searchValue)) return true; return true;
if (persona.Region?.toLowerCase().includes(searchValue))
return true;
} }
break; break;
default: default:
@@ -715,7 +727,7 @@ function TS_IndexElement(
} }
return 0; return 0;
} }
const searchValue = searchKeyEl.value.toLowerCase().trim(); const searchValue = searchKeyEl.value.toLowerCase().trim();
tablebody_EL.innerHTML = ""; tablebody_EL.innerHTML = "";
Object.entries(rows) Object.entries(rows)
@@ -747,6 +759,7 @@ function TS_IndexElement(
break; break;
case "comanda": case "comanda":
const tdComanda = document.createElement("td"); const tdComanda = document.createElement("td");
tdComanda.style.verticalAlign = "top";
const parsedComanda = JSON.parse(data.Comanda); const parsedComanda = JSON.parse(data.Comanda);
const precio = SC_priceCalc(parsedComanda)[0]; const precio = SC_priceCalc(parsedComanda)[0];
@@ -758,18 +771,26 @@ function TS_IndexElement(
const pre = document.createElement("pre"); const pre = document.createElement("pre");
pre.style.fontSize = "15px"; pre.style.fontSize = "15px";
pre.style.display = "inline-block"; pre.style.display = "inline-block";
pre.style.margin = "0";
pre.style.verticalAlign = "top";
pre.style.padding = "5px";
//looking like a post-it
pre.style.background = "rgba(255, 255, 0, 0.5)";
pre.style.border = "1px solid rgba(0, 0, 0, 0.2)";
pre.style.borderRadius = "5px";
pre.style.boxShadow = "2px 2px 5px rgba(0, 0, 0, 0.1)";
pre.style.height = "100%";
const spanPrecio = document.createElement("span"); const spanPrecio = document.createElement("span");
spanPrecio.style.fontSize = "20px"; spanPrecio.style.fontSize = "20px";
spanPrecio.innerHTML = spanPrecio.innerHTML =
SC_Personas[data.Persona].Puntos >= 10 SC_Personas[data.Persona].Puntos >= 10
? `Total: Gratis!(${precio}c)` ? `Total: Gratis!(${precio}c)`
: `Total: ${precio}c`; : `Total: ${precio}c`;
pre.innerHTML = "<b>Ticket de compra</b> ";
pre.appendChild(spanPrecio);
pre.appendChild(document.createTextNode("\n")); pre.appendChild(document.createTextNode("\n"));
pre.innerHTML += pre.innerHTML +=
SC_parse_short(parsedComanda) + "<hr>" + data.Notas; SC_parse_short(parsedComanda) + "<hr>" + data.Notas + "<hr>";
pre.appendChild(spanPrecio);
tdComanda.appendChild(pre); tdComanda.appendChild(pre);
new_tr.appendChild(tdComanda); new_tr.appendChild(tdComanda);
@@ -945,7 +966,7 @@ function TS_IndexElement(
} }
const PAGES = {}; const PAGES = {};
document.addEventListener("DOMContentLoaded", () => { function SetPages() {
Object.keys(PAGES).forEach((key) => { Object.keys(PAGES).forEach((key) => {
if (PAGES[key].Esconder == true) { if (PAGES[key].Esconder == true) {
return; return;
@@ -956,5 +977,24 @@ document.addEventListener("DOMContentLoaded", () => {
a.innerText = PAGES[key].Title; a.innerText = PAGES[key].Title;
document.getElementById("appendApps").append(a); document.getElementById("appendApps").append(a);
}); });
open_page(location.hash.replace("#", "")); }
document.addEventListener("DOMContentLoaded", () => {
SetPages();
document.getElementById("appendApps").style.display = "none";
document.getElementById("loading").style.display = "block";
}); });
var Booted = false;
getPeers();
setInterval(() => {
getPeers();
if (ConnectionStarted && !Booted) {
Booted = true;
document.getElementById("loading").style.display = "none";
if (!SUB_LOGGED_IN) {
open_page("login");
return;
}
document.getElementById("appendApps").style.display = "block";
open_page(location.hash.replace("#", ""));
}
}, 1500);

View File

@@ -22,4 +22,23 @@ const RELAYS = [
var SECRET = ""; var SECRET = "";
var SUB_LOGGED_IN = false; var SUB_LOGGED_IN = false;
var SUB_LOGGED_IN_DETAILS = false; var SUB_LOGGED_IN_DETAILS = false;
var SUB_LOGGED_IN_ID = false; var SUB_LOGGED_IN_ID = false;
if (urlParams.get("sublogin") != null) {
SUB_LOGGED_IN = true;
SUB_LOGGED_IN_ID = urlParams.get("sublogin");
SUB_LOGGED_IN_DETAILS = true;
setTimeout(() => {
SUB_LOGGED_IN_DETAILS = SC_Personas[SUB_LOGGED_IN_ID];
}, 1500);
}
function LogOutTeleSec() {
SUB_LOGGED_IN = false;
SUB_LOGGED_IN_DETAILS = false;
SUB_LOGGED_IN_ID = false;
document.getElementById("appendApps").style.display = "none";
document.getElementById("loading").style.display = "block";
//Remove sublogin from URL and reload
urlParams.delete("sublogin");
history.replaceState(null, "", "?" + urlParams.toString());
location.reload();
}

View File

@@ -14,48 +14,76 @@ function removeCache() {
location.reload(true); location.reload(true);
}); });
} }
function getPeers() { var AtLeastThreePeers = false;
var peerCount = 0; var ConnectionStarted = false;
var peerCountEl = document.getElementById("peerCount"); function formatPeerInfo(peer) {
var peerListEl = document.getElementById("peerList"); const wireType = peer.wire.constructor.name;
var list = document.createElement("ul"); let wireHType = wireType;
document.getElementById("peerPID").innerText = "PID " + gun.back("opt.pid"); let wireID = peer.id;
Object.values(gun.back("opt.peers")).forEach((peer) => {
if ( switch (wireType) {
peer.wire != undefined && case "WebSocket":
(peer.wire.readyState == 1 || peer.wire.readyState == "open") wireHType = "Web";
) { wireID = wireID.split("/")[2];
peerCount += 1; break;
var wireType = peer.wire.constructor.name; case "RTCDataChannel":
var wireHType = peer.wire.constructor.name; wireHType = "Mesh";
var wireID = peer.id; break;
switch (wireType) { }
case "WebSocket":
wireHType = "Web"; return { wireHType, wireID };
wireID = wireID.split("/")[2]; }
break;
case "RTCDataChannel": function isPeerConnected(peer) {
wireHType = "Mesh"; return peer.wire != undefined &&
wireID = peer.id; (peer.wire.readyState == 1 || peer.wire.readyState == "open");
} }
var el = document.createElement("li");
el.innerText = `Nodo ${wireHType}: ${wireID}`; function createPeerListElement(wireHType, wireID) {
list.append(el); const el = document.createElement("li");
} el.innerText = `Nodo ${wireHType}: ${wireID}`;
}); return el;
peerListEl.innerHTML = list.innerHTML; }
peerCountEl.innerText = peerCount;
function updateConnectionStatus(peerCount) {
const statusImage = peerCount < 3 ? "connect_ko.svg" : "connect_ok.svg";
document.getElementById("connectStatus").src = `static/ico/${statusImage}`;
if (peerCount < 3) { if (peerCount < 3) {
document.getElementById("connectStatus").src = "static/ico/connect_ko.svg"; if (!window.peerRetryCount) window.peerRetryCount = 0;
gun.opt({ peers: RELAYS }); window.peerRetryCount = (window.peerRetryCount + 1) % 3;
if (window.peerRetryCount === 0) {
gun.opt({ peers: RELAYS });
}
AtLeastThreePeers = false;
} else { } else {
document.getElementById("connectStatus").src = "static/ico/connect_ok.svg"; ConnectionStarted = true;
AtLeastThreePeers = true;
} }
} }
getPeers();
setInterval(() => { function getPeers() {
getPeers(); const peerCountEl = document.getElementById("peerCount");
}, 2500); const peerListEl = document.getElementById("peerList");
const list = document.createElement("ul");
document.getElementById("peerPID").innerText = "PID " + gun.back("opt.pid");
const connectedPeers = Object.values(gun.back("opt.peers"))
.filter(isPeerConnected)
.map(peer => {
const { wireHType, wireID } = formatPeerInfo(peer);
return createPeerListElement(wireHType, wireID);
});
connectedPeers.forEach(el => list.append(el));
peerListEl.innerHTML = list.innerHTML;
const peerCount = connectedPeers.length;
peerCountEl.innerText = peerCount;
updateConnectionStatus(peerCount);
}
function safeuuid(prefix = "AXLUID_") { function safeuuid(prefix = "AXLUID_") {
return prefix + crypto.randomUUID().split("-")[4]; return prefix + crypto.randomUUID().split("-")[4];
} }

View File

@@ -12,6 +12,7 @@
</head> </head>
<body> <body>
<img id="loading" src="load.gif" style="display: block; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: calc(100% - 50px); max-width: 400px;" />
<details class="supermesh-indicator"> <details class="supermesh-indicator">
<summary> <summary>
<b>SuperMesh</b><br /> <b>SuperMesh</b><br />

View File

@@ -3,9 +3,10 @@ PAGES.index = {
Title: "Inicio", Title: "Inicio",
index: function () { index: function () {
container.innerHTML = ` container.innerHTML = `
<h1>Inicio</h1> <h1>¡Hola, ${SUB_LOGGED_IN_DETAILS.Nombre}!</h1>
<em>Utiliza el menú superior para abrir un modulo</em> <em>Utiliza el menú superior para abrir un modulo</em>
<br><br> <br><br>
<button class="btn1" onclick="LogOutTeleSec()">Cerrar sesión</button>
`; `;
}, },
}; };

View File

@@ -15,7 +15,7 @@ PAGES.login = {
<button class="btn5" id="${btn_guardar}">Acceder</button> <button class="btn5" id="${btn_guardar}">Acceder</button>
<button class="btn1" id="${btn_reload}">Recargar lista</button> <button class="btn1" id="${btn_reload}">Recargar lista</button>
</fieldset> </fieldset>
<a style="color: rgb(240,240,240)">Acceso sin cuenta</a> <a style="color: rgb(240,240,240)">Acceso sin cuenta - No disponible</a>
`; `;
var divact = document.getElementById(div_actions); var divact = document.getElementById(div_actions);
addCategory_Personas( addCategory_Personas(