Pre-v2.0.0 adds groups, groups, security, and tab interface #83 #53

This commit is contained in:
Robert Strouse 2023-07-01 09:20:23 -07:00
parent a0c24ceb07
commit d228a21c83
19 changed files with 4095 additions and 1781 deletions

View file

@ -1 +1 @@
1.7.2
2.0.0

View file

@ -1,423 +0,0 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8">
<title>Configure CC1101</title>
<link rel="stylesheet" href="main.css" type="text/css" />
<link rel="stylesheet" href="icons.css" type="text/css" />
<style type="text/css">
body {
margin-top: 0px;
}
input[data-type="int8_t"],
input[data-type="uint8_t"] {
width: 47px;
text-align: right;
}
input[data-type="uint16_t"] {
width: 77px;
text-align: right;
}
input[data-type="float"] {
width: 77px;
text-align: right;
}
</style>
<script type="text/javascript">
let runRepair = false;
function runRemoteRepair() {
let obj = { address: parseInt(document.getElementById('fldRepairAddress').value, 10), command: 'Down', rcode: parseInt(document.getElementById('fldRepairRCode').value, 10), repeats: 1 };
if (runRepair) {
// Call the service.
console.log(obj);
putJSON('/sendRemoteCommand', obj, (err, ret) => {
console.log(ret);
document.getElementById('fldRepairRCode').value = obj.rcode + 1;
setTimeout(() => { runRemoteRepair() }, 1000);
});
}
}
function stopRemoteRepair() {
runRepair = false;
}
let baseUrl = ''; //'http://192.168.1.204'; This is the current server.
Number.prototype.round = function (dec) { return Number(Math.round(this + 'e' + dec) + 'e-' + dec); };
Number.prototype.fmt = function (format, empty) {
if (isNaN(this)) return empty || '';
if (typeof format === 'undefined') return this.toString();
let isNegative = this < 0;
let tok = ['#', '0'];
let pfx = '', sfx = '', fmt = format.replace(/[^#\.0\,]/g, '');
let dec = fmt.lastIndexOf('.') > 0 ? fmt.length - (fmt.lastIndexOf('.') + 1) : 0,
fw = '', fd = '', vw = '', vd = '', rw = '', rd = '';
let val = String(Math.abs(this).round(dec));
let ret = '', commaChar = ',', decChar = '.';
for (var i = 0; i < format.length; i++) {
let c = format.charAt(i);
if (c === '#' || c === '0' || c === '.' || c === ',')
break;
pfx += c;
}
for (let i = format.length - 1; i >= 0; i--) {
let c = format.charAt(i);
if (c === '#' || c === '0' || c === '.' || c === ',')
break;
sfx = c + sfx;
}
if (dec > 0) {
let dp = val.lastIndexOf('.');
if (dp === -1) {
val += '.'; dp = 0;
}
else
dp = val.length - (dp + 1);
while (dp < dec) {
val += '0';
dp++;
}
fw = fmt.substring(0, fmt.lastIndexOf('.'));
fd = fmt.substring(fmt.lastIndexOf('.') + 1);
vw = val.substring(0, val.lastIndexOf('.'));
vd = val.substring(val.lastIndexOf('.') + 1);
let ds = val.substring(val.lastIndexOf('.'), val.length);
for (let i = 0; i < fd.length; i++) {
if (fd.charAt(i) === '#' && vd.charAt(i) !== '0') {
rd += vd.charAt(i);
continue;
} else if (fd.charAt(i) === '#' && vd.charAt(i) === '0') {
var np = vd.substring(i);
if (np.match('[1-9]')) {
rd += vd.charAt(i);
continue;
}
else
break;
}
else if (fd.charAt(i) === '0' || fd.charAt(i) === '#')
rd += vd.charAt(i);
}
if (rd.length > 0) rd = decChar + rd;
}
else {
fw = fmt;
vw = val;
}
var cg = fw.lastIndexOf(',') >= 0 ? fw.length - fw.lastIndexOf(',') - 1 : 0;
var nw = Math.abs(Math.floor(this.round(dec)));
if (!(nw === 0 && fw.substr(fw.length - 1) === '#') || fw.substr(fw.length - 1) === '0') {
var gc = 0;
for (let i = vw.length - 1; i >= 0; i--) {
rw = vw.charAt(i) + rw;
gc++;
if (gc === cg && i !== 0) {
rw = commaChar + rw;
gc = 0;
}
}
if (fw.length > rw.length) {
var pstart = fw.indexOf('0');
if (pstart > 0) {
var plen = fw.length - pstart;
var pos = fw.length - rw.length - 1;
while (rw.length < plen) {
let pc = fw.charAt(pos);
if (pc === ',') pc = commaChar;
rw = pc + rw;
pos--;
}
}
}
}
if (isNegative) rw = '-' + rw;
if (rd.length === 0 && rw.length === 0) return '';
//console.log(pfx + rw + rd + sfx);
return pfx + rw + rd + sfx;
};
let fields = [
{ t: 'bool', i: 'printBuffer', d: 'Print the bytes received to the serial console', def: false },
{ t: 'bool', i: 'internalCCMode', d: 'Use internal transmission mode FIFO buffers.', def:true },
{ t: 'uint8_t', i: 'modulationMode', d: 'Modulation mode', o: [{ v: 0, n: '2-FSK' }, { v: 1, n: 'GFSK' }, { v: 2, n: 'ASK/OOK' }, { v: 3, n: '4-FSK' }, { v: 4, n: 'MSK' }] },
{ t: 'float', i: 'frequency', d: 'Basic frequency', def:433.24 },
{ t: 'float', i: 'deviation', d: 'Set the Frequency deviation in kHz. Value from 1.58 to 380.85. Default is 47.60 kHz.', def:47.6 },
{ t: 'uint8_t', i: 'channel', d: 'The channel number from 0 to 255', def:0 },
{ t: 'float', i: 'channelSpacing', d: 'Channel spacing in multiplied by the channel number and added to the base frequency in kHz. 25.39 to 405.45. Default 199.95', def:199.95 },
{ t: 'float', i: 'rxBandwidth', d: 'Receive bandwidth in kHz. Value from 58.03 to 812.50. Default is 812.50kHz', def:812.5 },
{ t: 'float', i: 'dataRate', d: 'The data rate in kBaud. 0.02 to 1621.83 Default is 99.97.', def:99.97 },
{ t: 'int8_t', i: 'txPower', d: 'Transmission power {-30, -20, -15, -10, -6, 0, 5, 7, 10, 11, 12}. Default is 12.', def:12 },
{
t: 'uint8_t', i: 'syncMode', d: 'Sync Mode', def:0, o: [
{ v: 0, n: 'No preamble/sync' },
{ v: 1, n: '16 sync word bits detected' },
{ v: 2, n: '16/16 sync words bits detected.' },
{ v: 3, n: '30/32 sync word bits detected,' },
{ v: 4, n: 'No preamble/sync carrier above threshold' },
{ v: 5, n: '15/16 + carrier above threshold.' },
{ v: 6, n: '16/16 + carrier-sense above threshold' },
{ v: 7, n: '0/32 + carrier-sense above threshold' }]
},
{ t: 'uint16_t', i: 'syncWordHigh', d: 'The High sync word used for the sync mode.', def:211 },
{ t: 'uint16_t', i: 'syncWordLow', d: 'The Low sync word used for the sync mode.', def:145 },
{
t: 'uint8_t', i: 'addrCheckMode', d: 'Address filter check mode', def:0, o: [
{ v: 0, n: 'No address filtration' },
{ v: 1, n: 'Check address without broadcast.' },
{ v: 2, n: 'Address check with 0 as broadcast.' },
{ v: 3, n: 'Address check with 0 or 255 as broadcast.' }]
},
{ t: 'uint8_t', i: 'checkAddr', d: 'Packet filter address depending on addrCheck settings.', def:0 },
{ t: 'bool', i: 'dataWhitening', d: 'Indicates whether data whitening should be applied.', def:false },
{
t: 'uint8_t', i: 'pktFormat', d: 'Packet formatting', def:0, o: [
{ v: 0, n: 'Use FIFO buffers for RX and TX' },
{ v: 1, n: 'Synchronous serial mode. RX on GDO0 and TX on either GDOx pins.' },
{ v: 2, n: 'Random TX mode. Send data using PN9 generator.' },
{ v: 3, n: 'Asynchronous serial mode. RX on GDO0 and TX on either GDOx pins.' }]
},
{
t: 'uint8_t', i: 'pktLengthMode', d: 'Type of packets', def:1, o: [
{ v: 0, n: 'Fixed packet length' },
{ v: 1, n: 'Variable packet length' },
{ v: 2, n: 'Infinite packet length' },
{ v: 3, n: 'Reserved' }]
},
{ t: 'uint8_t', i: 'pktLength', d: 'Packet length', def:0 },
{ t: 'bool', i: 'useCRC', d: 'Indicates whether CRC is to be used.', def:true },
{ t: 'bool', i: 'autoFlushCRC', d: 'Automatically flush RX FIFO when CRC fails. If more than one packet is in the buffer it too will be flushed.', def:false },
{ t: 'bool', i: 'disableDCFilter', d: 'Digital blocking filter for demodulator. Only for data rates <= 250k.', def:false },
{ t: 'bool', i: 'enableManchester', d: 'Enable/disable Manchester encoding.', def:false },
{ t: 'bool', i: 'enableFEC', d: 'Enable/disable forward error correction.', def:false },
{
t: 'uint8_t', i: 'minPreambleBytes', d: 'The minimum number of preamble bytes to be transmitted.', def:0, o: [
{ v: 0, n: '2bytes' },
{ v: 1, n: '3bytes' },
{ v: 2, n: '4bytes' },
{ v: 3, n: '6bytes' },
{ v: 4, n: '8bytes' },
{ v: 5, n: '12bytes' },
{ v: 6, n: '16bytes' },
{ v: 7, n: '24bytes' }]
},
{ t: 'uint8_t', i: 'pqtThreshold', d: 'Preamble quality estimator threshold.', def:0 },
{ t: 'bool', i: 'appendStatus', d: 'Appends the RSSI and LQI values to the TX packed as well as the CRC.', def: false }
];
function resetDefaults() {
for (let i = 0; i < fields.length; i++) {
let f = fields[i];
if (typeof f.def === 'undefined') continue;
let el = document.getElementById(`id_${f.i}`);
switch (f.t) {
case 'bool':
el.checked = f.def;
break;
default:
el.value = f.def;
break;
}
}
}
function loadConfig() {
let overlay = waitMessage(document.getElementById('divFields'));
getJSON('/getRadio', (err, radio) => {
overlay.remove();
if (err) {
console.log(err);
serviceError(document.getElementById('divFields'), err);
}
else {
console.log(radio);
let cfg = radio.config;
// Bind up all the fields.
let elems = document.querySelectorAll('[data-bind]');
for (let i = 0; i < elems.length; i++) {
let el = elems[i];
switch (el.dataset.type) {
case 'bool':
el.checked = cfg[el.dataset.bind];
break;
case 'float':
el.value = cfg[el.dataset.bind].fmt("#.##");
break;
default:
el.value = cfg[el.dataset.bind];
break;
}
}
}
});
}
function createCheckbox(f) { return `<input type="checkbox" id="id_${f.i}" name="${f.i}" data-type="${f.t}" data-bind="${f.bind || f.i}"></input><label for="${f.i}>${f.l || f.i}</label>`; }
function createNumberField(f) { return `<input type="number" id="id_${f.i}" name="${f.i}" data-type="${f.t}" data-bind="${f.bind || f.i}"></input > <label for="${f.i}>${f.l || f.i}</label>`; }
function createDropdown(f) {
let dd = `<select id="id_${f.i}" name="${f.i}" data-type="${f.t}"" data-bind="${f.bind || f.i}">`;
for (let i = 0; i < f.o.length; i++) {
let o = f.o[i];
dd += `<option value="${o.v}">${o.n}</option>`
}
dd += '</select>';
dd += `<label for="${f.i}>${f.l || f.i}</label>`;
return dd;
}
function createFields() {
let shtml = '<div id="divAttrs">';
for (let i = 0; i < fields.length; i++) {
let f = fields[i];
shtml += '<div class="cfg-attr"><div class="cfg-attr-field">'
switch (f.t) {
case 'bool':
shtml += createCheckbox(f);
break;
case 'uint8_t':
case 'int8_t':
case 'uint16_t':
case 'float':
case 'int8_t':
shtml += typeof f.o === 'undefined' ? createNumberField(f) : createDropdown(f);
break;
}
shtml += `</div><div class="cfg-attr-desc">${f.d}</div>`
shtml += '</div>';
}
shtml += '</div>';
document.getElementById('divFields').innerHTML = shtml;
}
function serviceError(el, err) {
let msg = '';
if (typeof err === 'string' && err.startsWith('{')) {
let e = JSON.parse(err);
if (typeof e !== 'undefined' && typeof e.desc === 'string') msg = e.desc;
else msg = err;
}
else if (typeof err === 'string') {
msg = err;
}
else if (typeof err === 'number') {
switch (err) {
case 404:
msg = `404: Service not found`;
break;
default:
msg = `${err}: Network HTTP Error`;
break;
}
}
else if (typeof err !== 'undefined') {
console.log(err);
if (typeof err.desc === 'string') msg = typeof err.desc !== 'undefined' ? err.desc : err.message;
}
return errorMessage(el, msg);
}
function errorMessage(el, msg) {
let div = document.createElement('div');
div.innerHTML = '<div class="innerError">' + msg + '</div><button type="button" onclick="clearErrors();">Close</button></div>';
div.classList.add('errorMessage');
el.appendChild(div);
return div;
}
function getJSON(url, cb) {
let xhr = new XMLHttpRequest();
xhr.open('GET', baseUrl + url, true);
xhr.responseType = 'json';
xhr.onload = () => {
let status = xhr.status;
cb(status === 200 ? null : status, xhr.response);
}
xhr.onerror = (evt) => {
cb(xhr.status || 500, xhr.statusText);
}
xhr.send();
}
function putJSON(url, data, cb) {
let xhr = new XMLHttpRequest();
console.log({ put: baseUrl + url, data: data });
xhr.open('PUT', baseUrl + url, true);
xhr.responseType = 'json';
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr.setRequestHeader('Accept', 'application/json');
xhr.onload = () => {
let status = xhr.status;
cb(status === 200 ? null : status, xhr.response);
}
xhr.onerror = (evt) => {
cb(xhr.status || 500, xhr.statusText);
}
xhr.send(JSON.stringify(data));
}
function waitMessage(el) {
let div = document.createElement('div');
div.innerHTML = '<div class="lds-roller"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div></div>';
div.classList.add('waitoverlay');
el.appendChild(div);
return div;
}
function clearErrors() {
let errors = document.querySelectorAll('div.errorMessage');
if (errors && errors.length > 0) errors.forEach((el) => { el.remove(); });
}
function saveSettings() {
let elems = document.querySelectorAll('[data-bind]');
let obj = {};
for (let i = 0; i < elems.length; i++) {
let el = elems[i];
switch (el.dataset.type) {
case 'bool':
obj[el.dataset.bind] = el.checked;
break;
case 'float':
obj[el.dataset.bind] = parseFloat(el.value);
break;
default:
obj[el.dataset.bind] = parseInt(el.value, 10);
break;
}
}
let overlay = waitMessage(document.getElementById('divFields'));
putJSON('/setRadioConfig', { config: obj }, (err, radio) => {
overlay.remove();
if (err) {
console.log(err);
serviceError(document.getElementById('divFields'), err);
}
else {
console.log(radio);
}
});
}
</script>
</head>
<body>
<div syle="white-space:nowrap;">
<label for="repairAddress">Repair Address</label>
<input id="fldRepairAddress" name="repairAddress" type="number" style="margin-right: 10px; text-align: right; display: inline-block; width: 127px;" value="4624451" />
<label for="repairRCode">Rolling Code</label>
<input id="fldRepairRCode" name="repairRCode" type="number" style="margin-right:10px;text-align:right;display:inline-block;width:127px;" value="1641" />
</div>
<div class="button-container">
<button id="btnRepairRemote" style="width:127px" onclick="runRepair = true; runRemoteRepair();">Repair Remote</button>
<button id="btnStopRepairRemote" style="width:127px" onclick="stopRemoteRepair();">Stop Repair</button>
</div>
<div id="divFields"></div>
<div class="button-container">
<button id="btnSaveSetting" type="button" style="display:inline-block;width:44%" onclick="resetDefaults();">
Reset Defaults
</button>
<button id="btnSaveSetting" type="button" style="display:inline-block;width:44%" onclick="saveSettings();">
Save Radio Settings
</button>
</div>
<script type="text/javascript">
createFields();
loadConfig();
</script>
</body>
</html>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

53
data/login.html Normal file
View file

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8">
<link rel="stylesheet" href="main.css?v=2.0.0" type="text/css" />
<link rel="stylesheet" href="widgets.css?v=2.0.0" type="text/css" />
<link rel="stylesheet" href="icons.css?v=2.0.0" type="text/css" />
<link rel="icon" type="image/png" href="favicon.png" />
<script type="text/javascript" src="index.js?v=2.0.0"></script>
</head>
<body onload="general.loadLogin();">
<div id="divContainer" class="container" data-securitytype="0">
<h1 style="text-align: center;"><img src="icon.png" style="width:127px;margin-left:1px;margin-top:-10px;" /></h1>
<div id="divLoginPnl" class="login-content" style="position:relative;">
<div style="max-width:270px;margin:0px auto;">
<form id="frmLogin" action="/login" method="post" class="login-form">
<input id="fldPin" type="hidden" name="pin">
<div id="divPinSecurity" style="display:none;">
<div class="field-group" style="text-align:center;">
<div id="fldPinEntry" style="display:inline-block;" onkeydown="general.pinKeyPressed(event);">
<input class="pin-digit" maxlength="1" data-bind="security.pin.d0" onfocus="general.pinDigitFocus(event);">
<input class="pin-digit" maxlength="1" data-bind="security.pin.d1" onfocus="general.pinDigitFocus(event);">
<input class="pin-digit" maxlength="1" data-bind="security.pin.d2" onfocus="general.pinDigitFocus(event);">
<input class="pin-digit" maxlength="1" data-bind="security.pin.d3" onfocus="general.pinDigitFocus(event);">
</div>
<label for="fldPinEntry" style="margin-top:7px;">Enter Pin</label>
</div>
</div>
<div id="divPasswordSecurity" style="display:none;">
<div class="field-group">
<input id="fldUsername" name="username" type="text" data-bind="security.username" length=32 placeholder="Username">
<label for="fldUsername">Username</label>
</div>
<div class="field-group">
<input id="fldPassword" name="password" type="password" data-bind="security.password" length=32 placeholder="Password">
<label for="fldPassword">Password</label>
</div>
</div>
<div style="text-align:center;"><span id="spanLoginMessage" style="color:red"></span></div>
<div class="button-container">
<button id="btnLogin" type="button" value="Submit" onclick="general.login();">
Login
</button>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
</script>
</body>
</html>

View file

@ -4,6 +4,29 @@
* {
box-sizing: border-box;
}
body {
color: #434343;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 14px;
background-color: #eeeeee;
margin-top: 77px;
box-sizing: border-box;
}
h1 {
text-align: center;
margin-bottom: 10px;
margin-top: 0px;
color: #939393;
font-size: 28px;
}
hr {
width:100%;
}
input[type="range"] {
accent-color: #00bcd4;
outline:none;
@ -12,6 +35,9 @@ input[type="range"] {
input[type="range"]:active {
outline: dotted 1px silver;
}
.button-outline {
-webkit-user-select: none;
-moz-user-select: none;
@ -48,34 +74,11 @@ input[type="range"] {
transform: rotate(7deg);
}
}
body {
color: #434343;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 14px;
background-color: #eeeeee;
margin-top: 77px;
box-sizing: border-box;
}
.container {
margin: 0 auto;
max-width: 450px;
padding: 20px;
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
background-color: #ffffff;
}
h1 {
text-align: center;
margin-bottom: 10px;
margin-top: 0px;
color: #939393;
font-size: 28px;
}
form {
margin-top:-18px;
}
form .field-group {
.field-group {
box-sizing: border-box;
clear: both;
padding: 4px 0;
@ -84,7 +87,7 @@ form .field-group {
width: 100%;
}
form .field-group1 {
.field-group1 {
box-sizing: border-box;
clear: both;
padding: 4px 0;
@ -93,7 +96,7 @@ form .field-group1 {
width: 100%;
}
form .field-group1 > span {
.field-group1 > span {
color: #757575;
display: inline-block;
margin: 0 0 5px 0;
@ -104,7 +107,7 @@ form .field-group1 {
font-weight: bold;
}
form .field-group > label {
.field-group > label {
display: block;
margin: 0px;
padding: 3px 0 0;
@ -116,11 +119,11 @@ form .field-group > label {
margin-top:-10px;
color:#00bcd4;
}
form .field-group1 > div.field-group {
.field-group1 > div.field-group {
display:inline-block;
width:auto;
}
::placeholder {
*::placeholder {
opacity: .5;
}
@ -156,9 +159,9 @@ select {
margin-bottom:14px;
}
form .field-group input[type=password],
form .field-group input[type=number],
form .field-group input[type=text] {
.field-group input[type=password],
.field-group input[type=number],
.field-group input[type=text] {
display: block;
width: 100%;
}
@ -214,7 +217,8 @@ a {
bottom: 7px;
border-bottom: 1px solid #00bcd4;
}
div.errorMessage {
div.prompt-message,
div.error-message {
position:absolute;
left:0px;
top:0px;
@ -229,17 +233,31 @@ div.errorMessage {
align-items:center;
align-content:center;
font-size:32px;
border-radius:5px;
border-radius:27px;
transition-duration:3s;
}
div.errorMessage > div {
div.prompt-message,
div.error-message > div {
padding:10px;
}
div.error-message > .sub-message {
font-size:14px;
}
div.socket-error {
opacity: 1;
font-size: 20px;
min-height: 277px;
z-index: 20001;
}
.prompt-message > .button-container {
text-align:center;
}
.prompt-message > .button-container > button {
width: calc(50% - 22px);
margin-left:7px;
margin-right:7px;
display:inline-block;
}
div.instructions {
position: absolute;
left: 0px;
@ -247,11 +265,11 @@ div.instructions {
width: 100%;
height: 100%;
color: white;
display: flex;
flex-wrap: wrap;
background: gray;
opacity: .9;
padding: 10px;
display: flex;
flex-wrap: wrap;
align-items: center;
align-content: center;
font-size: 20px;
@ -279,6 +297,45 @@ div.instructions {
border-bottom-width: 3px;
font-weight: bold;
}
.subtab-container {
margin-top:3px;
margin-left: 3px;
display: flex;
width: calc(100% - 7px);
margin-bottom: -1px;
overflow: visible;
border-bottom: 1px solid #ccc;
}
.subtab-container > span {
display:inline-block;
background:white;
margin-bottom:-1px;
padding-left: 10px;
padding-right:10px;
padding-top:5px;
padding-bottom:5px;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
cursor:pointer;
background:ghostwhite;
}
.subtab-container > span.selected {
border-bottom:none;
background:white;
}
.subtab-content {
display: block;
border-left: 1px solid #ccc;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-radius: 5px;
padding: 25px;
position: relative;
}
fieldset {
display: block;
border: 1px solid #ccc;
@ -371,7 +428,7 @@ span.strength {
button.disabled {
opacity:.3;
}
div.waitoverlay {
div.wait-overlay {
width: 100%;
height: 100%;
position: absolute;
@ -383,8 +440,9 @@ div.waitoverlay {
background:rgba(227, 226, 230, 0.46);
cursor:no-drop;
z-index:20000;
border-radius:27px;
}
div.waitoverlay > .lds-roller {
div.wait-overlay > .lds-roller {
z-index:1000;
opacity:1;
}
@ -463,10 +521,10 @@ div.waitoverlay > .lds-roller {
top: 63px;
left: 17px;
}
.lds-roller div:nth-child(8) {
animation-delay: -0.288s;
}
.lds-roller div:nth-child(8):after {
top: 56px;
left: 12px;
@ -486,17 +544,6 @@ div.waitoverlay > .lds-roller {
.radioPins > label {
text-align:center;
}
.somfyShade {
text-align:center;
padding-bottom:4px;
display:inline-table;
padding-left:4px;
padding-right:4px;
}
.somfyShade > div,
.somfyShade > span {
display:table-cell;
}
.button-outline {
background-color: #00bcd4;
border-radius:50%;
@ -507,6 +554,7 @@ div.waitoverlay > .lds-roller {
font-size:1.5em;
color:white;
}
.group-name,
.shade-name {
text-align:left;
width: 100%;
@ -517,6 +565,7 @@ div.waitoverlay > .lds-roller {
overflow:hidden;
vertical-align:middle;
}
.group-address,
.shade-address {
width:77px;
padding-left:2px;
@ -558,6 +607,7 @@ div.waitoverlay > .lds-roller {
display: block;
overflow: hidden;
}
.somfyGroupCtl,
.somfyShadeCtl {
height:60px;
border-bottom:dotted 2px gainsboro;
@ -576,12 +626,14 @@ div.waitoverlay > .lds-roller {
font-size: 48px;
position:relative;
}
.somfyGroupCtl .group-name,
.somfyShadeCtl .shade-name {
display:inline-block;
padding:7px;
vertical-align:middle;
width:100%;
}
}
.somfyGroupCtl .groupctl-name,
.somfyShadeCtl .shadectl-name {
font-size: 1.5em;
color: silver;
@ -590,18 +642,23 @@ div.waitoverlay > .lds-roller {
white-space: nowrap;
width: 100%;
}
.somfyGroupCtl label,
.somfyShadeCtl label {
color:silver;
}
.somfyGroupCtl .groupctl-mypos,
.somfyShadeCtl .shadectl-mypos {
white-space: nowrap;
font-size: 12px;
}
.somfyGroupCtl .groupctl-buttons,
.somfyShadeCtl .shadectl-buttons {
margin-top:3px;
float:right;
white-space:nowrap;
}
.somfyGroupCtl .groupctl-buttons .button-outline,
.somfyShadeCtl .shadectl-buttons .button-outline {
display: inline-block;
padding: 7px;
@ -675,30 +732,24 @@ div.eth-setting-line label {
color:mediumspringgreen;
}
div.frame-log {
position:absolute;
top:0px;
left:0px;
width:100%;
height:100%;
border-radius:27px;
border:solid 2px gray;
background:gainsboro;
}
div.frame-list {
position:relative;
width: calc(100% - 14px);
height: calc(100% - 147px);
left: 7px;
width: 100%;
max-height:357px;
background:white;
min-height:127px;
overflow-y:auto;
border:solid 1px silver;
border-bottom:solid 1px silver;
}
div.frame-header {
border-top-left-radius:5px;
border-top-right-radius:5px;
position: relative;
font-size: 12px;
background: #00bcd4;
width: calc(100% - 14px);
left: 7px;
width: 100%;
color:white;
padding-top:4px;
}

112
data/widgets.css Normal file
View file

@ -0,0 +1,112 @@
.container {
margin: 0 auto;
max-width: 450px;
padding: 20px;
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
background-color: #ffffff;
user-select: none;
position: relative;
border-radius: 27px;
}
.main.container {
min-height:327px;
}
.header-message {
text-align: center;
background: gainsboro;
color: gray;
margin-bottom: 7px;
text-transform: uppercase;
font-weight: bold;
padding: 4px;
border-radius: 5px;
}
.inst-overlay {
display: flex;
flex-wrap: wrap;
align-items: center;
align-content: flex-start;
position: absolute;
border-radius: 27px;
background: gray;
opacity: .9;
padding: 10px;
font-size: 20px;
height: auto;
min-height: 100%;
top: 0px;
left: 0px;
color: white;
}
.edit-grouplist,
.edit-motorlist {
overflow-y: auto;
max-height: 400px;
padding-top: 2px;
padding-bottom: 2px;
min-height: 147px;
}
.prompt-message .sub-message {
font-size: 17px;
padding-left: 10px;
padding-right: 10px;
}
.prompt-message .prompt-text {
text-align:center;
}
.promp-message > .inner-error,
.error-message > .inner-error {
width:100%;
}
.wizard[data-stepid="1"] .wizard-step:not([data-stepid="1"]) { display: none; }
.wizard[data-stepid="2"] .wizard-step:not([data-stepid="2"]) { display: none; }
.wizard[data-stepid="3"] .wizard-step:not([data-stepid="3"]) { display: none; }
.wizard[data-stepid="4"] .wizard-step:not([data-stepid="4"]) { display: none; }
.wizard[data-stepid="5"] .wizard-step:not([data-stepid="5"]) { display: none; }
.wizard[data-stepid="6"] .wizard-step:not([data-stepid="6"]) { display: none; }
.wizard[data-stepid="7"] .wizard-step:not([data-stepid="7"]) { display: none; }
.somfyGroup,
.somfyShade {
text-align: center;
padding-bottom: 4px;
display: inline-table;
padding-left: 4px;
padding-right: 4px;
}
.linked-shade > div,
.linked-shade > span,
.somfyGroup > div,
.somfyGroup > span,
.somfyShade > div,
.somfyShade > span {
display: table-cell;
padding-left:4px;
padding-right:4px;
}
.linked-shade {
width: 100%;
padding-bottom: 4px;
display: inline-table;
padding-left: 4px;
padding-right: 4px;
}
.linked-shade > .linkedshade-name { width: 100%; }
.pin-digit {
margin: 0 0.3rem;
padding: 0.5rem;
border: 1px solid #00bcd4;
border-radius:5px;
width: 50px;
height: 50px;
text-align: center;
font-size: 3rem;
}
.login-content {
display: block;
padding: 25px;
position: relative;
}