Initial commit
This commit is contained in:
6
Dockerfile
Normal file
6
Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
FROM docker.angie.software/angie:minimal
|
||||||
|
|
||||||
|
WORKDIR /usr/share/angie/html
|
||||||
|
|
||||||
|
COPY src/. .
|
||||||
|
|
||||||
29
README.md
Normal file
29
README.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# noolite-client
|
||||||
|
Simple web UI for lights control
|
||||||
|
|
||||||
|
Is the frontend for application [noolite-srv](https://gogs.dended.ru/ded/noolite-srv.git)
|
||||||
|
|
||||||
|
# Building
|
||||||
|
Just build docker image:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build . -t noolite-client
|
||||||
|
```
|
||||||
|
Or build crossplatform images:
|
||||||
|
```
|
||||||
|
docker buildx build --platform linux/amd64,linux/arm64 -t <your_tag> --push .
|
||||||
|
```
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
Install from docker registry:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker pull docker.dended.ru/noolite-client
|
||||||
|
```
|
||||||
|
|
||||||
|
# Using
|
||||||
|
Run docker container:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -p 8000:80 -v -d --restart unless-stopped noolite-srv
|
||||||
|
```
|
||||||
BIN
src/favicon.ico
Normal file
BIN
src/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
BIN
src/images/lamp.png
Normal file
BIN
src/images/lamp.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/images/off.png
Normal file
BIN
src/images/off.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
147
src/index.html
Normal file
147
src/index.html
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>nooLight</title>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-view {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: 500px;
|
||||||
|
min-width: 400px;
|
||||||
|
gap: 5px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
user-select: none;
|
||||||
|
height: 4vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button img {
|
||||||
|
margin-left: 10px;
|
||||||
|
height: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button span {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lamp-button {
|
||||||
|
flex: 1;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
height: 10vh; /* 10% от высоты экрана */
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lamp-button img {
|
||||||
|
height: 50%; /* 50% высоты кнопки */
|
||||||
|
}
|
||||||
|
|
||||||
|
.lamp-button span {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="list-view" id="listView">
|
||||||
|
<!-- Items will be dynamically added here -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
fetch('static/channels.js').
|
||||||
|
then( (response) => response.json() ).
|
||||||
|
then( (data) => appendData(data['groups']) ).
|
||||||
|
catch( (err) => console.log('error: ' + err) );
|
||||||
|
|
||||||
|
function switchLamp(channelId) {
|
||||||
|
fetch('noolite/switch/' + channelId).
|
||||||
|
catch( (err) => console.log('error: ' + err));
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendData(lightsModel) {
|
||||||
|
const listView = document.getElementById("listView");
|
||||||
|
|
||||||
|
lightsModel.forEach(group => {
|
||||||
|
const itemContainer = document.createElement("div");
|
||||||
|
itemContainer.classList.add("item");
|
||||||
|
|
||||||
|
if (group.groupName) {
|
||||||
|
const button = document.createElement("div");
|
||||||
|
button.classList.add("button");
|
||||||
|
const img = document.createElement("img");
|
||||||
|
img.src = "/images/off.png";
|
||||||
|
const span = document.createElement("span");
|
||||||
|
span.textContent = group.groupName;
|
||||||
|
button.appendChild(img);
|
||||||
|
button.appendChild(span);
|
||||||
|
itemContainer.appendChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = document.createElement("div");
|
||||||
|
row.classList.add("row");
|
||||||
|
|
||||||
|
group.channels.forEach(channel => {
|
||||||
|
const lampButton = document.createElement("div");
|
||||||
|
lampButton.classList.add("lamp-button");
|
||||||
|
|
||||||
|
const img = document.createElement("img");
|
||||||
|
img.src = "/images/lamp.png";
|
||||||
|
const span = document.createElement("span");
|
||||||
|
span.textContent = channel.name;
|
||||||
|
|
||||||
|
lampButton.appendChild(img);
|
||||||
|
lampButton.appendChild(span);
|
||||||
|
|
||||||
|
lampButton.addEventListener("click", () => switchLamp(channel.id) )
|
||||||
|
row.appendChild(lampButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
itemContainer.appendChild(row);
|
||||||
|
listView.appendChild(itemContainer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user