frontend with bootstrap

This commit is contained in:
2021-10-18 19:56:35 +01:00
parent 2faa518b32
commit 64560b2662
32 changed files with 60493 additions and 176 deletions
+3
View File
@@ -0,0 +1,3 @@
https://www.sliderrevolution.com/resources/css-range-slider/
https://iro.js.org/guide.html
https://javascript.info/websocket
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,481 @@
/*!
* Bootstrap Reboot v5.1.1 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
:root {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-bg: #fff;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
direction: ltr /* rtl:ignore */;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: left;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: left;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */
File diff suppressed because one or more lines are too long
@@ -0,0 +1,478 @@
/*!
* Bootstrap Reboot v5.1.1 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
:root {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-bg: #fff;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
direction: ltr ;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+17
View File
@@ -0,0 +1,17 @@
body {
/* min-width: 350px; */
overflow: scroll;
}
.IroColorPicker {
overflow: scroll;
white-space: nowrap;
width: max-content;
}
/* .IroColorPicker>.IroSlider, */
.IroColorPicker>.IroWheel {
margin-right: 12px;
}
+138
View File
@@ -0,0 +1,138 @@
<!doctype html>
<html>
<head>
<title>Config</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="description" content="Accueil">
<meta name="author" content="Tropicananass">
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" href="bootstrap-5.1.1-dist/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="index.css" type="text/css">
<script src="bootstrap-5.1.1-dist/js/bootstrap.min.js"></script>
<script src="iro.js"></script>
<script src="index_network_handler.js"></script>
<script src="index_ui_handler.js"></script>
</head>
<body class="bg-dark text-white">
<!-- Modal -->
<div class="modal fade text-black" id="reconnectBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="connectionLostLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="connectionLostLabel">Connection lost</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Try reconnecting in <span id="time-left">60s</span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" onclick="{timeout=1;}">Reconnect now</button>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row py-4 text-center" id="header">
<h1> Tropicananass Leds </h1>
</div>
<div class="row pt-2 gy-2">
<div class="col d-flex justify-content-center">
<form id="mode-input" class="btn-group" role="group" aria-label="Select mode">
<input type="radio" class="btn-check" name="mode-selection" id="test-mode" autocomplete="off" value="0" checked>
<input type="radio" class="btn-check" name="mode-selection" id="artnet-mode" autocomplete="off" value="1">
<input type="radio" class="btn-check" name="mode-selection" id="auto-mode" autocomplete="off" value="2">
<input type="radio" class="btn-check" name="mode-selection" id="manual-mode" autocomplete="off" value="3">
</form>
</div>
<div class="col d-flex justify-content-center">
<form id="pattern-input" class="btn-group" role="group" aria-label="Select pattern">
<input type="radio" class="btn-check" name="pattern-selection" id="pulse-pattern" autocomplete="off" value="0" checked>
<input type="radio" class="btn-check" name="pattern-selection" id="travel-pattern" autocomplete="off" value="1">
<input type="radio" class="btn-check" name="pattern-selection" id="strobe-pattern" autocomplete="off" value="2">
</form>
</div>
</div>
<div class="row pt-2 gy-2">
<legend class="col-12 col-sm-auto">Channel</legend>
<!-- <div class="col d-flex justify-content-center">
<form id="channelGlobal-input" class="btn-group" role="group" aria-label="Select channel">
<input type="radio" class="btn-check" name="channelGlobal-selection" id="all-channel" autocomplete="off" checked>
<input type="radio" class="btn-check" name="channelGlobal-selection" id="none-channel" autocomplete="off">
</form>
</div> -->
<div class="col d-flex justify-content-center">
<form id="channel-input" class="btn-group" role="group" aria-label="Select channel">
<!-- todo: Change to checkbox -->
<input type="radio" class="btn-check" name="channel-selection" id="all-channel" autocomplete="off" checked>
<input type="radio" class="btn-check" name="channel-selection" id="0-channel" autocomplete="off" checked>
<input type="radio" class="btn-check" name="channel-selection" id="1-channel" autocomplete="off" checked>
<input type="radio" class="btn-check" name="channel-selection" id="2-channel" autocomplete="off" checked>
<input type="radio" class="btn-check" name="channel-selection" id="3-channel" autocomplete="off" checked>
<input type="radio" class="btn-check" name="channel-selection" id="4-channel" autocomplete="off" checked>
<input type="radio" class="btn-check" name="channel-selection" id="5-channel" autocomplete="off" checked>
<input type="radio" class="btn-check" name="channel-selection" id="6-channel" autocomplete="off" checked>
<input type="radio" class="btn-check" name="channel-selection" id="7-channel" autocomplete="off" checked>
</form>
</div>
</div>
<div class="row pt-2 gy-2">
<label class="form-label col-9 col-sm-2 text-sm-end" for="formControlRange">Sensitivity</label>
<span class="col-3 col-sm-1 text-end">50</span>
<div class="col col-sm-9">
<input type="range" class="form-range" id="formControlRange" oninput="rangeCallback(this)">
</div>
</div>
<div class="row pt-2 gy-2">
<label class="form-label col-9 col-sm-2 text-sm-end" for="formControlRange">Gravity</label>
<span class="col-3 col-sm-1 text-end">50</span>
<div class="col col-sm-9">
<input type="range" class="form-range col-auto" id="formControlRange" oninput="rangeCallback(this)">
</div>
</div>
<div class="row pt-2 gy-2">
<div class="col">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="modulateColor" onclick="colorModulateCallback(this)">
<label class="form-check-label" for="modulateColor">Modulate color</label>
</div>
</div>
</div>
<div class="row pt-2 gy-2">
<div id="mainPicker" class="col d-flex justify-content-center"></div>
<div id="modulationPicker" class="col d-none d-flex justify-content-center"></div>
</div>
<div class="row pt-2 gy-2">
<label class="form-label col-9 col-sm-2 text-sm-end" for="formControlRange">Modulation speed</label>
<span class="col-3 col-sm-auto text-end" id="rangeval">50</span>
<div class="col col-sm-9">
<input type="range" class="form-range col-auto" id="formControlRange" oninput="rangeCallback(this)">
</div>
</div>
<div class="row pt-2 gy-2">
<label class="form-label col-9 col-sm-2 text-sm-end" for="formControlRange">Freq</label>
<span class="col-3 col-sm-auto text-end" id="rangeval">50</span>
<div class="col col-sm-9">
<input type="range" class="form-range col-auto" id="formControlRange" oninput="rangeCallback(this)">
</div>
</div>
</div>
</body>
</html>
<script src="index.js"></script>
+77
View File
@@ -0,0 +1,77 @@
var socket;
var timer;
var timeout;
var modal = new bootstrap.Modal(document.getElementById("reconnectBackdrop"));
var slectedChannel = 8;
function addLabelAndListener(name, callback) {
let rootElement = document.getElementById(name + "-input")
rootElement.addEventListener('click', callback);
let inputArray = rootElement.elements[name + "-selection"];
for (let inputIndex = 0; inputIndex < inputArray.length; inputIndex++) {
let element = inputArray[inputIndex]
let label = document.createElement("label");
label.classList.add("btn");
label.classList.add("btn-outline-primary");
label.classList.add("text-capitalize");
label.setAttribute("for", element.id);
labelText = element.id.split('-')[0];
label.innerHTML = labelText;
element.insertAdjacentElement("afterend", label);
}
}
addLabelAndListener("mode", modeSelectCallback);
addLabelAndListener("pattern", patternSelectCallback);
addLabelAndListener("channel", channelSelectCallback);
// addLabelAndListener("channelGlobal", channelSelectCallback);
var colorPicker = new iro.ColorPicker('#mainPicker', {
colors: [
'hsl(0, 100, 50)', // pure red
'hsl(180, 50, 100)' // pure green
],
layout: [{
component: iro.ui.Wheel,
options: {
wheelLightness: false
}
}, {
component: iro.ui.Slider,
options: {
sliderType: 'value'
}
}],
layoutDirection: 'horizontal',
// display: "flex",
width: 250,
margin: 0,
handleRadius: 14
});
var modulationPicker = new iro.ColorPicker('#modulationPicker', {
colors: [
'hsl(0, 100, 50)', // pure red
],
layout: [{
component: iro.ui.Wheel,
options: {
wheelLightness: false
}
}, {
component: iro.ui.Slider,
options: {
sliderType: 'value'
}
}],
layoutDirection: 'horizontal',
// display: "flex",
width: 250,
margin: 0,
handleRadius: 14
});
reconnect();
colorPicker.on("color:change", colorChangeCallback);
modulationPicker.on("color:change", colorChangeCallback);
@@ -0,0 +1,51 @@
function wait_reconnection() {
--timeout;
document.getElementById("time-left").innerHTML = timeout + "s";
if (timeout == 0) {
clearInterval(timer);
reconnect();
}
}
function reconnect() {
socket = new WebSocket("ws://tropicananass.ovh:8080");
timeout = 60;
socket.onopen = function(e) {
console.log("[open] ws: Connection established");
clearInterval(timer);
modal.hide();
};
socket.onmessage = function(event) {
console.log(`[message] ws: Data received from server: ${event.data}`);
let message = event.data.split(":");
let command = message[0];
let payload = message[1];
console.log(command + ", " + payload);
switch (command) {
case 'm':
document.getElementById("mode-input").elements["mode-selection"][payload].checked = true;
break;
default:
break;
}
};
socket.onclose = function(event) {
if (event.wasClean) {
console.log(`[close] ws: Connection closed cleanly, code=${event.code} reason=${event.reason}`);
} else {
// e.g. server process killed or network down
// event.code is usually 1006 in this case
console.log('[close] ws: Connection died');
timer = setInterval(wait_reconnection, 1000);
modal.show();
}
};
socket.onerror = function(error) {
console.log(`[error] ws: ${error.message}`);
};
}
@@ -0,0 +1,69 @@
function modeSelectCallback(event) {
// todo: disable form on this != auto
if (event.target.nodeName == 'INPUT') {
console.log("m:" + event.target.value);
if (socket.readyState == WebSocket.OPEN) {
socket.send("m:" + event.target.value);
}
}
}
function patternSelectCallback(event) {
// todo: disable form on this != auto
if (event.target.nodeName == 'INPUT') {
console.log("p:" + event.target.value);
if (socket.readyState == WebSocket.OPEN) {
socket.send("p:" + event.target.value);
}
}
}
function channelSelectCallback(event) {
if (event.target.nodeName == 'INPUT') {
channel = event.target.id.split("-")[0];
if (channel == "all") {
// inputArray = document.getElementById("channel-input").elements[name + "channel-selection"]
// for (let inputIndex = 0; inputIndex < inputArray.length; inputIndex++) {
// inputArray[inputIndex].checked = false;
// }
selectedChannel = 8;
} else if (channel == "none") {
inputArray = document.getElementById("channel-input").elements[name + "channel-selection"]
for (let inputIndex = 0; inputIndex < inputArray.length; inputIndex++) {
inputArray[inputIndex].checked = false;
}
selectedChannel = -1;
} else {
inputArray = document.getElementById("channelGlobal-input").elements[name + "channelGlobal-selection"]
for (let inputIndex = 0; inputIndex < inputArray.length; inputIndex++) {
inputArray[inputIndex].checked = false;
}
selectedChannel = channel;
}
console.log("channel:" + selectedChannel);
}
}
var eventd;
function colorModulateCallback(element) {
eventd = element;
if (element.checked) {
document.getElementById("modulationPicker").classList.remove("d-none");
} else {
document.getElementById("modulationPicker").classList.add("d-none");
}
console.log("s: " + element.checked);
}
function colorChangeCallback(color) {
console.log("c: " + color.index + ", h: " + color.hsl.h + ", s: " + color.hsl.s + ", l: " + color.hsl.l + "}");
if (socket.readyState == WebSocket.OPEN) {
socket.send("c:" + color.index + "," + color.hsl.h + "," + color.hsl.s + "," + color.hsl.l);
}
}
function rangeCallback(element) {
eventd = this
element.parentNode.parentElement.getElementsByTagName('span')[0].innerText = element.value;
}
File diff suppressed because one or more lines are too long