This commit is contained in:
2025-03-31 00:22:21 +03:00
commit 38f2a05107
146 changed files with 66771 additions and 0 deletions

116
web/lib/app.js Normal file
View File

@@ -0,0 +1,116 @@
let USER = {};
// Определение ID главного блока
let app = document.getElementById('app');
// Конфигурация роутера
Router.config({ mode: 'history' });
async function appReload() {
location.reload();
// Router.navigate(window.location.pathname, false).check();
// // Закрытие старого соединения WebSocket
// if (socket) socket.close(1000, "Перезапуск соединения");
// listEntrances = []
// listApartment = []
}
const Rotation = async () => {
const result = confirm(`Ви бажаєте провести ротацію територій між групами?`);
if (result) {
let rotationButton = document.getElementById('rotationButton-title');
rotationButton.innerText = "Зачекайте";
let uuid = localStorage.getItem("uuid");
const URL = `${CONFIG.api}rotation`;
await fetch(URL, {
method: 'GET',
headers: {
"Content-Type": "application/json, text/plain, */*",
"Authorization": uuid
}
})
.then(response => response.json())
.then(data => {
console.log(data);
rotationButton.innerText = 'Ротація завершилась успішно!';
Territory.house.setHTML();
Territory.homestead.setHTML();
setTimeout(() => {
rotationButton.innerText = "Провести ротацію";
}, 3000);
})
.catch(err => {
console.log(err);
rotationButton.innerText = "Помилка ротації!";
})
}
}
// Функция загрузки приложения
window.addEventListener('load', async function () {
console.log('[OS] ', detectOS());
if (window.matchMedia('(display-mode: standalone)').matches) {
if (detectOS() == 'Android') {
document.getElementById('navigation').dataset.state = '';
} else if (detectOS() == 'iOS') {
document.getElementById('navigation').dataset.state = 'ios';
localStorage.setItem('backToTop', 'false');
} else if (detectOS() == 'MacOS') {
document.getElementById('navigation').dataset.state = 'ios';
localStorage.setItem('backToTop', 'false');
} else {
document.getElementById('navigation').dataset.state = '';
}
}
let userInput = () => {
let h = prompt("Введіть ваше посилання з UUID:");
if (h) {
h = h.replace("https://sheep-service.com/?uuid=", "");
h = h.replace("https://sheep-service.com?uuid=", "");
h = h.replace("https://sheep-service.com?/hash=", "");
h = h.replace("https://sheep-service.com?hash=", "");
localStorage.setItem("uuid", h)
return h;
}
};
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('uuid')) {
localStorage.setItem("uuid", urlParams.get('uuid'))
}
if (urlParams.get('hash')) {
localStorage.setItem("uuid", urlParams.get('hash'))
}
let uuid = localStorage.getItem("uuid") ? localStorage.getItem("uuid") : userInput();
if (uuid) {
const URL = `${CONFIG.api}auth`;
USER = await fetch(URL, {
method: 'GET',
headers: {
"Content-Type": "application/json, text/plain, */*",
"Authorization": uuid
}
}).then((response) => response.json());
console.log("USER Info: ", USER);
if (USER.administrator.uuid || USER.moderator.uuid) document.getElementById("li-sheeps").style.display = "";
if (USER.administrator.uuid || (USER.moderator.uuid && USER.moderator.can_add_schedule)) document.getElementById("li-schedule").style.display = "";
if (USER.administrator.uuid || (USER.moderator.uuid && USER.moderator.can_manager_territory)) document.getElementById("li-territory").style.display = "";
if (USER.administrator.uuid || USER.can_view_stand) document.getElementById("li-stand").style.display = "";
}
Router.check().listen();
});

View File

@@ -0,0 +1,5 @@
clipboard = (text) => {
navigator.clipboard.writeText(text)
.then(() => console.log("Текст скопійовано!"))
.catch(err => console.error(err))
}

View File

@@ -0,0 +1,20 @@
let colorGroup = (number) => {
switch (number) {
case 1:
return "#c1ae4d"
case 2:
return "#93c14d"
case 3:
return "#4dc1a7"
case 4:
return "#4d90c1"
case 5:
return "#654dc1"
case 6:
return "#c14db7"
case 7:
return "#c1734d"
default:
return "#C14D4D"
}
}

View File

@@ -0,0 +1,35 @@
detectBrowser = () => {
const userAgent = navigator.userAgent;
let browser = "unkown";
// Detect browser name
browser = (/ucbrowser/i).test(userAgent) ? 'UCBrowser' : browser;
browser = (/edg/i).test(userAgent) ? 'Edge' : browser;
browser = (/googlebot/i).test(userAgent) ? 'GoogleBot' : browser;
browser = (/chromium/i).test(userAgent) ? 'Chromium' : browser;
browser = (/firefox|fxios/i).test(userAgent) && !(/seamonkey/i).test(userAgent) ? 'Firefox' : browser;
browser = (/; msie|trident/i).test(userAgent) && !(/ucbrowser/i).test(userAgent) ? 'IE' : browser;
browser = (/chrome|crios/i).test(userAgent) && !(/opr|opera|chromium|edg|ucbrowser|googlebot/i).test(userAgent) ? 'Chrome' : browser;;
browser = (/safari/i).test(userAgent) && !(/chromium|edg|ucbrowser|chrome|crios|opr|opera|fxios|firefox/i).test(userAgent) ? 'Safari' : browser;
browser = (/opr|opera/i).test(userAgent) ? 'Opera' : browser;
// detect browser version
switch (browser) {
case 'UCBrowser': return `${browser}/${browserVersion(userAgent,/(ucbrowser)\/([\d\.]+)/i)}`;
case 'Edge': return `${browser}/${browserVersion(userAgent,/(edge|edga|edgios|edg)\/([\d\.]+)/i)}`;
case 'GoogleBot': return `${browser}/${browserVersion(userAgent,/(googlebot)\/([\d\.]+)/i)}`;
case 'Chromium': return `${browser}/${browserVersion(userAgent,/(chromium)\/([\d\.]+)/i)}`;
case 'Firefox': return `${browser}/${browserVersion(userAgent,/(firefox|fxios)\/([\d\.]+)/i)}`;
case 'Chrome': return `${browser}/${browserVersion(userAgent,/(chrome|crios)\/([\d\.]+)/i)}`;
case 'Safari': return `${browser}/${browserVersion(userAgent,/(safari)\/([\d\.]+)/i)}`;
case 'Opera': return `${browser}/${browserVersion(userAgent,/(opera|opr)\/([\d\.]+)/i)}`;
case 'IE': const version = browserVersion(userAgent,/(trident)\/([\d\.]+)/i);
// IE version is mapped using trident version
// IE/8.0 = Trident/4.0, IE/9.0 = Trident/5.0
return version ? `${browser}/${parseFloat(version) + 4.0}` : `${browser}/7.0`;
default: return `unknown/0.0.0.0`;
}
}
browserVersion = (userAgent,regex) => {
return userAgent.match(regex) ? userAgent.match(regex)[2] : null;
}

View File

@@ -0,0 +1,12 @@
function detectOS() {
const platform = navigator.platform.toLowerCase(),
iosPlatforms = ['iphone', 'ipad', 'ipod', 'ipod touch'];
if (platform.includes('mac')) return 'MacOS';
if (iosPlatforms.includes(platform)) return 'iOS';
if (platform.includes('win')) return 'Windows';
if (/android/.test(navigator.userAgent.toLowerCase())) return 'Android';
if (/linux/.test(platform)) return 'Linux';
return 'unknown';
}

View File

@@ -0,0 +1,9 @@
let formattedDate = (unix_timestamp) => {
if(!unix_timestamp) return
let date = new Date(unix_timestamp);
let year = date.getFullYear() >= 10 ? date.getFullYear() : "0" + date.getFullYear();
let month = (date.getMonth() + 1) >= 10 ? (date.getMonth() + 1) : "0" + (date.getMonth() + 1);
let weekday = date.getDate() >= 10 ? date.getDate() : "0" + date.getDate();
return weekday + '.' + month + '.' + year;
}

View File

@@ -0,0 +1,283 @@
.marker-icon,
.marker-icon:focus {
background-color: #ffffff;
border: 1px solid #3388ff;
border-radius: 50%;
margin: -4px 0 0 -4px !important;
width: 6px !important;
height: 6px !important;
outline: 0;
transition: opacity ease 0.3s;
}
.marker-icon-middle,
.marker-icon-middle:focus {
opacity: 0.7;
margin: -6px 0 0 -6px !important;
width: 10px !important;
height: 10px !important;
}
.leaflet-pm-draggable {
cursor: move !important;
}
.cursor-marker {
cursor: crosshair;
pointer-events: none;
opacity: 0;
}
.cursor-marker.visible {
opacity: 1 !important;
}
.leaflet-pm-invalid {
stroke: red;
transition: fill ease 0s, stroke ease 0s;
}
.rect-style-marker,
.rect-start-marker {
opacity: 0;
}
.rect-style-marker.visible,
.rect-start-marker.visible {
opacity: 1 !important;
}
.vertexmarker-disabled {
opacity: 0.7;
}
.pm-text-marker {
width: 0;
height: 0;
}
.pm-textarea {
background-color: #fff;
color: #000;
resize: none;
border: none;
outline: 0;
cursor: pointer;
border-radius: 3px;
padding-left: 7px;
padding-bottom: 0;
padding-top: 4px;
}
.leaflet-pm-draggable .pm-textarea {
cursor: move;
}
.pm-textarea:focus,
.pm-textarea:focus-within,
.pm-textarea:focus-visible,
.pm-textarea:active {
border: 2px solid #000;
outline: 0;
}
.pm-textarea.pm-disabled {
border: none;
user-select: none;
}
.pm-textarea.pm-hasfocus {
cursor: auto;
}
.leaflet-pm-toolbar {
}
.leaflet-pm-toolbar .leaflet-buttons-control-button {
padding: 5px;
box-sizing: border-box;
position: relative;
z-index: 3;
}
.leaflet-pm-toolbar
.leaflet-pm-actions-container
a.leaflet-pm-action:first-child:not(.pos-right),
.leaflet-pm-toolbar
.leaflet-pm-actions-container
a.leaflet-pm-action:last-child.pos-right {
border-radius: 0;
}
.leaflet-pm-toolbar .button-container a.leaflet-buttons-control-button {
border-radius: 0;
}
.leaflet-pm-toolbar
.button-container:last-child
a.leaflet-buttons-control-button {
border-radius: 0 0 2px 2px;
}
.leaflet-pm-toolbar
.button-container:first-child
a.leaflet-buttons-control-button {
border-radius: 2px 2px 0 0;
}
.leaflet-pm-toolbar
.button-container:last-child
a.leaflet-buttons-control-button {
border-bottom: none;
}
.leaflet-pm-toolbar .control-fa-icon {
font-size: 19px;
line-height: 24px;
}
.leaflet-pm-toolbar .control-icon {
width: 100%;
height: 100%;
box-sizing: border-box;
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
}
.leaflet-pm-toolbar .leaflet-pm-icon-marker {
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjUgKDY3NDY5KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5BdG9tcy9JY29ucy9Ub29scy9NYXJrZXI8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNMTUuNSwyNC44NzgyOTU5IEMxNS4yOTA5MjAxLDI0Ljg3NzIyMTkgMTUuMTc0NDg1NywyNC44NDY3ODE3IDE0LjY1OTA4NjYsMjQuMjM1NDE2MyBDMTAuMjE5Njk1NSwxOS40MTE4MDU0IDgsMTUuNTAxNDM5MiA4LDEyLjUwNDMxNzcgQzgsOC4zNTk3OTc0NiAxMS4zNTc4NjQ0LDUgMTUuNSw1IEMxOS42NDIxMzU2LDUgMjMsOC4zNTk3OTc0NiAyMywxMi41MDQzMTc3IEMyMywxNyAxOC4yODc4MjE3LDIxLjkyNjgzNzggMTYuMzMzNjYwMSwyNC4yNDQwMTg2IEMxNS44MjI0NjIyLDI0Ljg1MDE4MDIgMTUuNzA5MDc5OSwyNC44NzkzNjk5IDE1LjUsMjQuODc4Mjk1OSBaIE0xNS41LDE1LjUzMjY5NDggQzE3LjI3NTIwMSwxNS41MzI2OTQ4IDE4LjcxNDI4NTcsMTQuMTE4MDAwNCAxOC43MTQyODU3LDEyLjM3Mjg4NjQgQzE4LjcxNDI4NTcsMTAuNjI3NzcyMyAxNy4yNzUyMDEsOS4yMTMwNzc5MiAxNS41LDkuMjEzMDc3OTIgQzEzLjcyNDc5OSw5LjIxMzA3NzkyIDEyLjI4NTcxNDMsMTAuNjI3NzcyMyAxMi4yODU3MTQzLDEyLjM3Mjg4NjQgQzEyLjI4NTcxNDMsMTQuMTE4MDAwNCAxMy43MjQ3OTksMTUuNTMyNjk0OCAxNS41LDE1LjUzMjY5NDggWiIgaWQ9InBhdGgtMSI+PC9wYXRoPgogICAgPC9kZWZzPgogICAgPGcgaWQ9IlN5bWJvbHMiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJBdG9tcy9JY29ucy9Ub29scy9NYXJrZXIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zLjAwMDAwMCwgLTMuMDAwMDAwKSI+CiAgICAgICAgICAgIDxtYXNrIGlkPSJtYXNrLTIiIGZpbGw9IndoaXRlIj4KICAgICAgICAgICAgICAgIDx1c2UgeGxpbms6aHJlZj0iI3BhdGgtMSI+PC91c2U+CiAgICAgICAgICAgIDwvbWFzaz4KICAgICAgICAgICAgPHVzZSBpZD0iTWFzayIgZmlsbD0iIzVCNUI1QiIgZmlsbC1ydWxlPSJub256ZXJvIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==);
}
.leaflet-pm-toolbar .leaflet-pm-icon-polygon {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgPGRlZnM+CiAgICA8cGF0aCBpZD0icG9seWdvbi1hIiBkPSJNMTkuNDIwNjg5Miw5LjE2NTA5NzI1IEMxOS4xNTIzNjgxLDguNjY5OTI5MTQgMTksOC4xMDI3NTgzMSAxOSw3LjUgQzE5LDUuNTY3MDAzMzggMjAuNTY3MDAzNCw0IDIyLjUsNCBDMjQuNDMyOTk2Niw0IDI2LDUuNTY3MDAzMzggMjYsNy41IEMyNiw5LjI2MzIzNTk1IDI0LjY5NjE0NzEsMTAuNzIxOTQwNyAyMywxMC45NjQ1NTU2IEwyMywxOS4wMzU0NDQ0IEMyNC42OTYxNDcxLDE5LjI3ODA1OTMgMjYsMjAuNzM2NzY0IDI2LDIyLjUgQzI2LDI0LjQzMjk5NjYgMjQuNDMyOTk2NiwyNiAyMi41LDI2IEMyMC43MzY3NjQsMjYgMTkuMjc4MDU5MywyNC42OTYxNDcxIDE5LjAzNTQ0NDQsMjMgTDEwLjk2NDU1NTYsMjMgQzEwLjcyMTk0MDcsMjQuNjk2MTQ3MSA5LjI2MzIzNTk1LDI2IDcuNSwyNiBDNS41NjcwMDMzOCwyNiA0LDI0LjQzMjk5NjYgNCwyMi41IEM0LDIwLjU2NzAwMzQgNS41NjcwMDMzOCwxOSA3LjUsMTkgQzguMTAyNzU4MzEsMTkgOC42Njk5MjkxNCwxOS4xNTIzNjgxIDkuMTY1MDk3MjUsMTkuNDIwNjg5MiBMMTkuNDIwNjg5Miw5LjE2NTA5NzI1IFogTTIwLjgzNDkwNzMsMTAuNTc5MzA2MyBMMTAuNTc5MzEwOCwyMC44MzQ5MDI3IEMxMC42MDg2NzMxLDIwLjg4OTA4ODggMTAuNjM2NjQ2OSwyMC45NDQxMzcyIDEwLjY2MzE4NDQsMjEgTDE5LjMzNjgxNTYsMjEgQzE5LjY4MjU3NzUsMjAuMjcyMTU0IDIwLjI3MjE1NCwxOS42ODI1Nzc1IDIxLDE5LjMzNjgxNTYgTDIxLDEwLjY2MzE4NDQgQzIwLjk0NDEzNzIsMTAuNjM2NjQ2OSAyMC44ODkwODg4LDEwLjYwODY3MzEgMjAuODM0OTAyNywxMC41NzkzMTA4IFogTTIyLjUsOSBDMjMuMzI4NDI3MSw5IDI0LDguMzI4NDI3MTIgMjQsNy41IEMyNCw2LjY3MTU3Mjg4IDIzLjMyODQyNzEsNiAyMi41LDYgQzIxLjY3MTU3MjksNiAyMSw2LjY3MTU3Mjg4IDIxLDcuNSBDMjEsOC4zMjg0MjcxMiAyMS42NzE1NzI5LDkgMjIuNSw5IFogTTIyLjUsMjQgQzIzLjMyODQyNzEsMjQgMjQsMjMuMzI4NDI3MSAyNCwyMi41IEMyNCwyMS42NzE1NzI5IDIzLjMyODQyNzEsMjEgMjIuNSwyMSBDMjEuNjcxNTcyOSwyMSAyMSwyMS42NzE1NzI5IDIxLDIyLjUgQzIxLDIzLjMyODQyNzEgMjEuNjcxNTcyOSwyNCAyMi41LDI0IFogTTcuNSwyNCBDOC4zMjg0MjcxMiwyNCA5LDIzLjMyODQyNzEgOSwyMi41IEM5LDIxLjY3MTU3MjkgOC4zMjg0MjcxMiwyMSA3LjUsMjEgQzYuNjcxNTcyODgsMjEgNiwyMS42NzE1NzI5IDYsMjIuNSBDNiwyMy4zMjg0MjcxIDYuNjcxNTcyODgsMjQgNy41LDI0IFoiLz4KICA8L2RlZnM+CiAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMyAtMykiPgogICAgPG1hc2sgaWQ9InBvbHlnb24tYiIgZmlsbD0iI2ZmZiI+CiAgICAgIDx1c2UgeGxpbms6aHJlZj0iI3BvbHlnb24tYSIvPgogICAgPC9tYXNrPgogICAgPHVzZSBmaWxsPSIjNUI1QjVCIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHhsaW5rOmhyZWY9IiNwb2x5Z29uLWEiLz4KICAgIDxnIGZpbGw9IiM1QjVCNUIiIG1hc2s9InVybCgjcG9seWdvbi1iKSI+CiAgICAgIDxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIzMCIvPgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg==);
}
.leaflet-pm-toolbar .leaflet-pm-icon-polyline {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgPGRlZnM+CiAgICA8cGF0aCBpZD0ibGluZS1hIiBkPSJNOS4xNjUwOTcyNSwxOS40MjA2ODkyIEwxOC40MjA2ODkyLDEwLjE2NTA5NzMgQzE4LjE1MjM2ODEsOS42Njk5MjkxNCAxOCw5LjEwMjc1ODMxIDE4LDguNSBDMTgsNi41NjcwMDMzOCAxOS41NjcwMDM0LDUgMjEuNSw1IEMyMy40MzI5OTY2LDUgMjUsNi41NjcwMDMzOCAyNSw4LjUgQzI1LDEwLjQzMjk5NjYgMjMuNDMyOTk2NiwxMiAyMS41LDEyIEMyMC44OTcyNDE3LDEyIDIwLjMzMDA3MDksMTEuODQ3NjMxOSAxOS44MzQ5MDI3LDExLjU3OTMxMDggTDEwLjU3OTMxMDgsMjAuODM0OTAyNyBDMTAuODQ3NjMxOSwyMS4zMzAwNzA5IDExLDIxLjg5NzI0MTcgMTEsMjIuNSBDMTEsMjQuNDMyOTk2NiA5LjQzMjk5NjYyLDI2IDcuNSwyNiBDNS41NjcwMDMzOCwyNiA0LDI0LjQzMjk5NjYgNCwyMi41IEM0LDIwLjU2NzAwMzQgNS41NjcwMDMzOCwxOSA3LjUsMTkgQzguMTAyNzU4MzEsMTkgOC42Njk5MjkxNCwxOS4xNTIzNjgxIDkuMTY1MDk3MjUsMTkuNDIwNjg5MiBaIE0yMS41LDEwIEMyMi4zMjg0MjcxLDEwIDIzLDkuMzI4NDI3MTIgMjMsOC41IEMyMyw3LjY3MTU3Mjg4IDIyLjMyODQyNzEsNyAyMS41LDcgQzIwLjY3MTU3MjksNyAyMCw3LjY3MTU3Mjg4IDIwLDguNSBDMjAsOS4zMjg0MjcxMiAyMC42NzE1NzI5LDEwIDIxLjUsMTAgWiBNNy41LDI0IEM4LjMyODQyNzEyLDI0IDksMjMuMzI4NDI3MSA5LDIyLjUgQzksMjEuNjcxNTcyOSA4LjMyODQyNzEyLDIxIDcuNSwyMSBDNi42NzE1NzI4OCwyMSA2LDIxLjY3MTU3MjkgNiwyMi41IEM2LDIzLjMyODQyNzEgNi42NzE1NzI4OCwyNCA3LjUsMjQgWiIvPgogIDwvZGVmcz4KICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zIC0zKSI+CiAgICA8bWFzayBpZD0ibGluZS1iIiBmaWxsPSIjZmZmIj4KICAgICAgPHVzZSB4bGluazpocmVmPSIjbGluZS1hIi8+CiAgICA8L21hc2s+CiAgICA8dXNlIGZpbGw9IiM1QjVCNUIiIGZpbGwtcnVsZT0ibm9uemVybyIgeGxpbms6aHJlZj0iI2xpbmUtYSIvPgogICAgPGcgZmlsbD0iIzVCNUI1QiIgbWFzaz0idXJsKCNsaW5lLWIpIj4KICAgICAgPHJlY3Qgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K);
}
.leaflet-pm-toolbar .leaflet-pm-icon-circle {
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjUgKDY3NDY5KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5BdG9tcy9JY29ucy9Ub29scy9DaXJjbGU8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNMTguMjg5Nzc1MSw2Ljc4NjAyMjc1IEMxOC44OTI0MTMxLDYuMjk0NjQ5ODEgMTkuNjYxNzk3LDYgMjAuNSw2IEMyMi40MzI5OTY2LDYgMjQsNy41NjcwMDMzOCAyNCw5LjUgQzI0LDEwLjMzODIwMyAyMy43MDUzNTAyLDExLjEwNzU4NjkgMjMuMjEzOTc3MiwxMS43MTAyMjQ5IEMyMy43MTk1OTksMTIuODcxMjA1MyAyNCwxNC4xNTI4NTcxIDI0LDE1LjUgQzI0LDIwLjc0NjcwNTEgMTkuNzQ2NzA1MSwyNSAxNC41LDI1IEM5LjI1MzI5NDg4LDI1IDUsMjAuNzQ2NzA1MSA1LDE1LjUgQzUsMTAuMjUzMjk0OSA5LjI1MzI5NDg4LDYgMTQuNSw2IEMxNS44NDcxNDI5LDYgMTcuMTI4Nzk0Nyw2LjI4MDQwMDk4IDE4LjI4OTc3NTEsNi43ODYwMjI3NSBaIE0xNy4xNTA0MjI4LDguNDgxNzU4NiBDMTYuMzI2MzU4MSw4LjE3MDM5MjM2IDE1LjQzMzA3NzcsOCAxNC41LDggQzEwLjM1Nzg2NDQsOCA3LDExLjM1Nzg2NDQgNywxNS41IEM3LDE5LjY0MjEzNTYgMTAuMzU3ODY0NCwyMyAxNC41LDIzIEMxOC42NDIxMzU2LDIzIDIyLDE5LjY0MjEzNTYgMjIsMTUuNSBDMjIsMTQuNTY2OTIyMyAyMS44Mjk2MDc2LDEzLjY3MzY0MTkgMjEuNTE4MjQxNCwxMi44NDk1NzcyIEMyMS4xOTYwMzgzLDEyLjk0NzM5NjggMjAuODU0MTYyMiwxMyAyMC41LDEzIEMxOC41NjcwMDM0LDEzIDE3LDExLjQzMjk5NjYgMTcsOS41IEMxNyw5LjE0NTgzNzc4IDE3LjA1MjYwMzIsOC44MDM5NjE2OSAxNy4xNTA0MjI4LDguNDgxNzU4NiBaIE0xNC41LDE3IEMxMy42NzE1NzI5LDE3IDEzLDE2LjMyODQyNzEgMTMsMTUuNSBDMTMsMTQuNjcxNTcyOSAxMy42NzE1NzI5LDE0IDE0LjUsMTQgQzE1LjMyODQyNzEsMTQgMTYsMTQuNjcxNTcyOSAxNiwxNS41IEMxNiwxNi4zMjg0MjcxIDE1LjMyODQyNzEsMTcgMTQuNSwxNyBaIE0yMC41LDExIEMyMS4zMjg0MjcxLDExIDIyLDEwLjMyODQyNzEgMjIsOS41IEMyMiw4LjY3MTU3Mjg4IDIxLjMyODQyNzEsOCAyMC41LDggQzE5LjY3MTU3MjksOCAxOSw4LjY3MTU3Mjg4IDE5LDkuNSBDMTksMTAuMzI4NDI3MSAxOS42NzE1NzI5LDExIDIwLjUsMTEgWiIgaWQ9InBhdGgtMSI+PC9wYXRoPgogICAgPC9kZWZzPgogICAgPGcgaWQ9IlN5bWJvbHMiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJBdG9tcy9JY29ucy9Ub29scy9DaXJjbGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zLjAwMDAwMCwgLTMuMDAwMDAwKSI+CiAgICAgICAgICAgIDxtYXNrIGlkPSJtYXNrLTIiIGZpbGw9IndoaXRlIj4KICAgICAgICAgICAgICAgIDx1c2UgeGxpbms6aHJlZj0iI3BhdGgtMSI+PC91c2U+CiAgICAgICAgICAgIDwvbWFzaz4KICAgICAgICAgICAgPHVzZSBpZD0iTWFzayIgZmlsbD0iIzVCNUI1QiIgZmlsbC1ydWxlPSJub256ZXJvIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgPGcgaWQ9IkF0b21zL0NvbG9yL0dyZXkiIG1hc2s9InVybCgjbWFzay0yKSIgZmlsbD0iIzVCNUI1QiI+CiAgICAgICAgICAgICAgICA8cmVjdCBpZD0iUmVjdGFuZ2xlIiB4PSIwIiB5PSIwIiB3aWR0aD0iMzAiIGhlaWdodD0iMzAiPjwvcmVjdD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+);
}
.leaflet-pm-toolbar .leaflet-pm-icon-circle-marker {
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KCjxzdmcgdmlld0JveD0iMCAwIDEwMCAxMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjNUI1QjVCIiBzdHJva2Utd2lkdGg9IjgiCiAgICAgZmlsbD0ibm9uZSI+CjxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjM1Ii8+CiAgPGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgcj0iMyIgZmlsbD0iIzVCNUI1QiIvPgo8L3N2Zz4=);
}
.leaflet-pm-toolbar .leaflet-pm-icon-rectangle {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgPGRlZnM+CiAgICA8cGF0aCBpZD0icmVjdGFuZ2xlLWEiIGQ9Ik0yMywxMC45NjQ1NTU2IEwyMywxOS4wMzU0NDQ0IEMyNC42OTYxNDcxLDE5LjI3ODA1OTMgMjYsMjAuNzM2NzY0IDI2LDIyLjUgQzI2LDI0LjQzMjk5NjYgMjQuNDMyOTk2NiwyNiAyMi41LDI2IEMyMC43MzY3NjQsMjYgMTkuMjc4MDU5MywyNC42OTYxNDcxIDE5LjAzNTQ0NDQsMjMgTDEwLjk2NDU1NTYsMjMgQzEwLjcyMTk0MDcsMjQuNjk2MTQ3MSA5LjI2MzIzNTk1LDI2IDcuNSwyNiBDNS41NjcwMDMzOCwyNiA0LDI0LjQzMjk5NjYgNCwyMi41IEM0LDIwLjczNjc2NCA1LjMwMzg1MjkzLDE5LjI3ODA1OTMgNywxOS4wMzU0NDQ0IEw3LDEwLjk2NDU1NTYgQzUuMzAzODUyOTMsMTAuNzIxOTQwNyA0LDkuMjYzMjM1OTUgNCw3LjUgQzQsNS41NjcwMDMzOCA1LjU2NzAwMzM4LDQgNy41LDQgQzkuMjYzMjM1OTUsNCAxMC43MjE5NDA3LDUuMzAzODUyOTMgMTAuOTY0NTU1Niw3IEwxOS4wMzU0NDQ0LDcgQzE5LjI3ODA1OTMsNS4zMDM4NTI5MyAyMC43MzY3NjQsNCAyMi41LDQgQzI0LjQzMjk5NjYsNCAyNiw1LjU2NzAwMzM4IDI2LDcuNSBDMjYsOS4yNjMyMzU5NSAyNC42OTYxNDcxLDEwLjcyMTk0MDcgMjMsMTAuOTY0NTU1NiBaIE0yMSwxMC42NjMxODQ0IEMyMC4yNzIxNTQsMTAuMzE3NDIyNSAxOS42ODI1Nzc1LDkuNzI3ODQ1OTggMTkuMzM2ODE1Niw5IEwxMC42NjMxODQ0LDkgQzEwLjMxNzQyMjUsOS43Mjc4NDU5OCA5LjcyNzg0NTk4LDEwLjMxNzQyMjUgOSwxMC42NjMxODQ0IEw5LDE5LjMzNjgxNTYgQzkuNzI3ODQ1OTgsMTkuNjgyNTc3NSAxMC4zMTc0MjI1LDIwLjI3MjE1NCAxMC42NjMxODQ0LDIxIEwxOS4zMzY4MTU2LDIxIEMxOS42ODI1Nzc1LDIwLjI3MjE1NCAyMC4yNzIxNTQsMTkuNjgyNTc3NSAyMSwxOS4zMzY4MTU2IEwyMSwxMC42NjMxODQ0IFogTTcuNSw5IEM4LjMyODQyNzEyLDkgOSw4LjMyODQyNzEyIDksNy41IEM5LDYuNjcxNTcyODggOC4zMjg0MjcxMiw2IDcuNSw2IEM2LjY3MTU3Mjg4LDYgNiw2LjY3MTU3Mjg4IDYsNy41IEM2LDguMzI4NDI3MTIgNi42NzE1NzI4OCw5IDcuNSw5IFogTTIyLjUsOSBDMjMuMzI4NDI3MSw5IDI0LDguMzI4NDI3MTIgMjQsNy41IEMyNCw2LjY3MTU3Mjg4IDIzLjMyODQyNzEsNiAyMi41LDYgQzIxLjY3MTU3MjksNiAyMSw2LjY3MTU3Mjg4IDIxLDcuNSBDMjEsOC4zMjg0MjcxMiAyMS42NzE1NzI5LDkgMjIuNSw5IFogTTIyLjUsMjQgQzIzLjMyODQyNzEsMjQgMjQsMjMuMzI4NDI3MSAyNCwyMi41IEMyNCwyMS42NzE1NzI5IDIzLjMyODQyNzEsMjEgMjIuNSwyMSBDMjEuNjcxNTcyOSwyMSAyMSwyMS42NzE1NzI5IDIxLDIyLjUgQzIxLDIzLjMyODQyNzEgMjEuNjcxNTcyOSwyNCAyMi41LDI0IFogTTcuNSwyNCBDOC4zMjg0MjcxMiwyNCA5LDIzLjMyODQyNzEgOSwyMi41IEM5LDIxLjY3MTU3MjkgOC4zMjg0MjcxMiwyMSA3LjUsMjEgQzYuNjcxNTcyODgsMjEgNiwyMS42NzE1NzI5IDYsMjIuNSBDNiwyMy4zMjg0MjcxIDYuNjcxNTcyODgsMjQgNy41LDI0IFoiLz4KICA8L2RlZnM+CiAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMyAtMykiPgogICAgPG1hc2sgaWQ9InJlY3RhbmdsZS1iIiBmaWxsPSIjZmZmIj4KICAgICAgPHVzZSB4bGluazpocmVmPSIjcmVjdGFuZ2xlLWEiLz4KICAgIDwvbWFzaz4KICAgIDx1c2UgZmlsbD0iIzVCNUI1QiIgZmlsbC1ydWxlPSJub256ZXJvIiB4bGluazpocmVmPSIjcmVjdGFuZ2xlLWEiLz4KICAgIDxnIGZpbGw9IiM1QjVCNUIiIG1hc2s9InVybCgjcmVjdGFuZ2xlLWIpIj4KICAgICAgPHJlY3Qgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K);
}
.leaflet-pm-toolbar .leaflet-pm-icon-delete {
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjUgKDY3NDY5KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5BdG9tcy9JY29ucy9Ub29scy9FcmFzZXI8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNMTcuNzg3NDIxOSwxOC40ODEyNTUyIEwxMS42NDgwMDc5LDEzLjM0OTgxODQgTDYuNDA0NjYwMDksMTkuMzgxNjAwMSBMMTAuNTUzOTE1NiwyMi45ODg0OTI5IEwxMy44NjkzNCwyMi45ODg0OTI5IEwxNy43ODc0MjE5LDE4LjQ4MTI1NTIgWiBNMTYuNTA3NDI1MiwyMi45ODg0OTI5IEwyNi4wMDAwMDAyLDIyLjk4ODQ5MjkgTDI2LjAwMDAwMDIsMjQuOTg4NDkyOSBMMTAuMDAwMDAwMiwyNC45ODg0OTI5IEw5LjgwNzA4MzEzLDI0Ljk4ODQ5MjkgTDUuMDkyNTQyMDQsMjAuODkxMDE5MiBDNC4yNTg5MTI4NSwyMC4xNjYzNTY0IDQuMTcwNTc4MTQsMTguOTAzMTExMiA0Ljg5NTI0MDkzLDE4LjA2OTQ4MiBMMTYuMDQ4MjQ0NCw1LjIzOTQxOTE2IEMxNi43NzI5MDcyLDQuNDA1Nzg5OTggMTguMDM2MTUyNSw0LjMxNzQ1NTI2IDE4Ljg2OTc4MTYsNS4wNDIxMTgwNiBMMjQuOTA3NDU4MywxMC4yOTA1OTAzIEMyNS43NDEwODc1LDExLjAxNTI1MzEgMjUuODI5NDIyMiwxMi4yNzg0OTgzIDI1LjEwNDc1OTQsMTMuMTEyMTI3NSBMMTYuNTA3NDI1MiwyMi45ODg0OTI5IFoiIGlkPSJwYXRoLTEiPjwvcGF0aD4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJTeW1ib2xzIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0iQXRvbXMvSWNvbnMvVG9vbHMvRXJhc2VyIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMy4wMDAwMDAsIC0zLjAwMDAwMCkiPgogICAgICAgICAgICA8bWFzayBpZD0ibWFzay0yIiBmaWxsPSJ3aGl0ZSI+CiAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICA8L21hc2s+CiAgICAgICAgICAgIDx1c2UgaWQ9IkNvbWJpbmVkLVNoYXBlIiBmaWxsPSIjNUI1QjVCIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+);
}
.leaflet-pm-toolbar .leaflet-pm-icon-edit {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgPGRlZnM+CiAgICA8cGF0aCBpZD0iZWRpdF9hbmNob3ItYSIgZD0iTTEzLjUsMTEgQzExLjU2NzAwMzQsMTEgMTAsOS40MzI5OTY2MiAxMCw3LjUgQzEwLDUuNTY3MDAzMzggMTEuNTY3MDAzNCw0IDEzLjUsNCBDMTUuNDMyOTk2Niw0IDE3LDUuNTY3MDAzMzggMTcsNy41IEMxNyw5LjQzMjk5NjYyIDE1LjQzMjk5NjYsMTEgMTMuNSwxMSBaIE0xMy41LDkgQzE0LjMyODQyNzEsOSAxNSw4LjMyODQyNzEyIDE1LDcuNSBDMTUsNi42NzE1NzI4OCAxNC4zMjg0MjcxLDYgMTMuNSw2IEMxMi42NzE1NzI5LDYgMTIsNi42NzE1NzI4OCAxMiw3LjUgQzEyLDguMzI4NDI3MTIgMTIuNjcxNTcyOSw5IDEzLjUsOSBaIE0xMi4wMDAyODg5LDcuNTI5NzM4OTMgQzEyLjAxMjU5ODMsOC4xNjI3MzY3MiAxMi40MTcwMTk3LDguNjk5NjY0MyAxMi45ODA3MTExLDguOTA3Njc5NjYgTDMsMTUgTDMsMTMgTDEyLjAwMDI4ODksNy41Mjk3Mzg5MyBaIE0xNC4yMTcyNzIyLDYuMTgyMjg0NzIgTDE5LjQ1MzEyNSwzIEwyMi42NTg5MzU1LDMgTDE0Ljk4OTEwMiw3LjY4MTczODg1IEMxNC45OTYyOTcxLDcuNjIyMTY0NTkgMTUsNy41NjE1MTQ3MiAxNSw3LjUgQzE1LDYuOTMxMzgzODEgMTQuNjgzNjA5OCw2LjQzNjY2NDUgMTQuMjE3MjcyMiw2LjE4MjI4NDcyIFogTTIzLjQ0MzQwNDIsMTkuMjg1MTczNiBMMjAuMTI4Mjc5OSwxOS4yODUxNzM2IEwyMS44NzI5OTgzLDIzLjUzNDk1MjUgQzIxLjk5NDUyOTYsMjMuODI5NTc3MyAyMS44NTU2NTQ2LDI0LjE1OTkyMDkgMjEuNTc3ODczNCwyNC4yODQ5MjA4IEwyMC4wNDE0Njc1LDI0Ljk1NDUxNDIgQzE5Ljc1NTA2MTMsMjUuMDc5NTE0MSAxOS40MzM4NzM4LDI0LjkzNjY3MDQgMTkuMzEyMzQyNiwyNC42NTA5NTE4IEwxNy42NTQ0MzY3LDIwLjYxNTQ1NDEgTDE0Ljk0NjE4NzMsMjMuNDAxMDE1MSBDMTQuNTg1MjgxMSwyMy43NzIxNzExIDE0LDIzLjQ4NjA0NjMgMTQsMjIuOTk5MjY1MyBMMTQsOS41NzE4MzUzMyBDMTQsOS4wNTkzMzU2MSAxNC42MjI1MzExLDguODA5NDkyIDE0Ljk0NjE1Niw5LjE3MDA4NTU1IEwyMy44MzQwMjkyLDE4LjMxMjAxNzkgQzI0LjE5MjUyOTEsMTguNjYxMzYxNSAyMy45Mjc5OTc5LDE5LjI4NTE3MzYgMjMuNDQzNDA0MiwxOS4yODUxNzM2IFoiLz4KICA8L2RlZnM+CiAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMyAtMykiPgogICAgPG1hc2sgaWQ9ImVkaXRfYW5jaG9yLWIiIGZpbGw9IiNmZmYiPgogICAgICA8dXNlIHhsaW5rOmhyZWY9IiNlZGl0X2FuY2hvci1hIi8+CiAgICA8L21hc2s+CiAgICA8dXNlIGZpbGw9IiM1QjVCNUIiIGZpbGwtcnVsZT0ibm9uemVybyIgeGxpbms6aHJlZj0iI2VkaXRfYW5jaG9yLWEiLz4KICAgIDxnIGZpbGw9IiM1QjVCNUIiIG1hc2s9InVybCgjZWRpdF9hbmNob3ItYikiPgogICAgICA8cmVjdCB3aWR0aD0iMzAiIGhlaWdodD0iMzAiLz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=);
}
.leaflet-pm-toolbar .leaflet-pm-icon-drag {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgPGRlZnM+CiAgICA8cGF0aCBpZD0ibW92ZS1hIiBkPSJNMjEsMTQgTDIxLDEwIEwyNywxNSBMMjEsMjAgTDIxLDE2IEwxNiwxNiBMMTYsMjEgTDIwLDIxIEwxNSwyNyBMMTAsMjEgTDE0LDIxIEwxNCwxNiBMOSwxNiBMOSwyMCBMMywxNSBMOSwxMCBMOSwxNCBMMTQsMTQgTDE0LDkgTDEwLDkgTDE1LDMgTDIwLDkgTDE2LDkgTDE2LDE0IEwyMSwxNCBaIi8+CiAgPC9kZWZzPgogIDxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTMgLTMpIj4KICAgIDxtYXNrIGlkPSJtb3ZlLWIiIGZpbGw9IiNmZmYiPgogICAgICA8dXNlIHhsaW5rOmhyZWY9IiNtb3ZlLWEiLz4KICAgIDwvbWFzaz4KICAgIDx1c2UgZmlsbD0iI0Q4RDhEOCIgeGxpbms6aHJlZj0iI21vdmUtYSIvPgogICAgPGcgZmlsbD0iIzVCNUI1QiIgbWFzaz0idXJsKCNtb3ZlLWIpIj4KICAgICAgPHJlY3Qgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K);
}
.leaflet-pm-toolbar .leaflet-pm-icon-cut {
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjUgKDY3NDY5KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5BdG9tcy9JY29ucy9Ub29scy9TY2lzc29yczwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPgogICAgICAgIDxwYXRoIGQ9Ik0xMi45NjkxNTc0LDEzLjQ5Mzk0MzUgTDIxLjAzMTcwMzIsNS41NDE2NzAxMyBMMjMuNDY0OTQ5OSw1LjY3NzIyOTU3IEwxNy4wNDcwNzEzLDE0LjUxMDY4MTYgTDI3LjU2NjAzMzYsMTcuMTMzMzUzNSBMMjUuNzg5MTk0NCwxOC44MDEyNTg4IEwxNC41ODU0OTUxLDE3Ljg5ODc1MDYgTDEzLjY0ODc5NTUsMTkuMTg4MDA3IEMxMy43OTQ2MzksMTkuMjY1MDk1OCAxMy45MzY3OTg1LDE5LjM1MzQ0MTcgMTQuMDc0MTM3NywxOS40NTMyMjQ1IEMxNS42Mzc5NjQ4LDIwLjU4OTQxMTQgMTUuOTg0NjM1NywyMi43NzgyMDUyIDE0Ljg0ODQ0ODgsMjQuMzQyMDMyNCBDMTMuNzEyMjYxOSwyNS45MDU4NTk1IDExLjUyMzQ2ODEsMjYuMjUyNTMwNCA5Ljk1OTY0MDk2LDI1LjExNjM0MzUgQzguMzk1ODEzODQsMjMuOTgwMTU2NSA4LjA0OTE0Mjk2LDIxLjc5MTM2MjcgOS4xODUzMjk4NiwyMC4yMjc1MzU2IEM5Ljc0NTg3Mjc2LDE5LjQ1NjAxNDUgMTAuNTYyNjE4OCwxOC45ODA3NDc1IDExLjQzNDEyMTgsMTguODMzNjQwNyBMMTIuNjgwNTY1NiwxNy4xMTgwNTc5IEwxMi41MjM5NzI0LDE2LjM3NDcyMTYgTDExLjk1MDY5MzIsMTUuMzAxMjM5MSBMOS44OTMxMDY0NiwxNC43ODgyMjUxIEM5LjEzMDkzNzk2LDE1LjIzNTcyNjEgOC4xOTk3Nzg1NCwxNS4zOTY2NDQ3IDcuMjc0NDUzNTUsMTUuMTY1OTM1MiBDNS4zOTg4NzUxOSwxNC42OTgzMDEgNC4yNTc1MTA5NCwxMi43OTg3NTE5IDQuNzI1MTQ1MTUsMTAuOTIzMTczNiBDNS4xOTI3NzkzNSw5LjA0NzU5NTE5IDcuMDkyMzI4NDYsNy45MDYyMzA5NCA4Ljk2NzkwNjgyLDguMzczODY1MTUgQzEwLjg0MzQ4NTIsOC44NDE0OTkzNSAxMS45ODQ4NDk0LDEwLjc0MTA0ODUgMTEuNTE3MjE1MiwxMi42MTY2MjY4IEMxMS40NzYxNDY0LDEyLjc4MTM0NDkgMTEuNDI0MDMzNSwxMi45NDA0MDAxIDExLjM2MTg2MjcsMTMuMDkzMTk5OSBMMTIuOTY5MTU3NCwxMy40OTM5NDM1IFogTTcuNzU4Mjk3MzUsMTMuMjI1MzQzOCBDOC41NjIxMTY2NCwxMy40MjU3NTg0IDkuMzc2MjA5MTIsMTIuOTM2NjAyMyA5LjU3NjYyMzc4LDEyLjEzMjc4MyBDOS43NzcwMzg0NCwxMS4zMjg5NjM3IDkuMjg3ODgyMzMsMTAuNTE0ODcxMyA4LjQ4NDA2MzAzLDEwLjMxNDQ1NjYgQzcuNjgwMjQzNzMsMTAuMTE0MDQxOSA2Ljg2NjE1MTI2LDEwLjYwMzE5OCA2LjY2NTczNjYsMTEuNDA3MDE3MyBDNi40NjUzMjE5NCwxMi4yMTA4MzY2IDYuOTU0NDc4MDUsMTMuMDI0OTI5MSA3Ljc1ODI5NzM1LDEzLjIyNTM0MzggWiBNMTAuODAzMzYzOSwyMS40MDMxMDYxIEMxMC4zMTY0MjY2LDIyLjA3MzMxNzcgMTAuNDY0OTk5OCwyMy4wMTEzNzIyIDExLjEzNTIxMTUsMjMuNDk4MzA5NSBDMTEuODA1NDIzMSwyMy45ODUyNDY3IDEyLjc0MzQ3NzYsMjMuODM2NjczNSAxMy4yMzA0MTQ4LDIzLjE2NjQ2MTkgQzEzLjcxNzM1MjEsMjIuNDk2MjUwMiAxMy41Njg3Nzg4LDIxLjU1ODE5NTcgMTIuODk4NTY3MiwyMS4wNzEyNTg1IEMxMi4yMjgzNTU2LDIwLjU4NDMyMTIgMTEuMjkwMzAxMSwyMC43MzI4OTQ1IDEwLjgwMzM2MzksMjEuNDAzMTA2MSBaIiBpZD0icGF0aC0xIj48L3BhdGg+CiAgICA8L2RlZnM+CiAgICA8ZyBpZD0iU3ltYm9scyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IkF0b21zL0ljb25zL1Rvb2xzL1NjaXNzb3JzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMy4wMDAwMDAsIC0zLjAwMDAwMCkiPgogICAgICAgICAgICA8bWFzayBpZD0ibWFzay0yIiBmaWxsPSJ3aGl0ZSI+CiAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICA8L21hc2s+CiAgICAgICAgICAgIDx1c2UgaWQ9Ik1hc2siIGZpbGw9IiM1QjVCNUIiIGZpbGwtcnVsZT0ibm9uemVybyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTYuMDkzMTk0LCAxNS42NjMzNTEpIHJvdGF0ZSgtMzIuMDAwMDAwKSB0cmFuc2xhdGUoLTE2LjA5MzE5NCwgLTE1LjY2MzM1MSkgIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==);
}
.leaflet-pm-toolbar .leaflet-pm-icon-snapping {
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDU3LjEgKDgzMDg4KSAtIGh0dHBzOi8vc2tldGNoLmNvbSAtLT4KICAgIDx0aXRsZT5BdG9tcy9JY29ucy9Ub29scy9NYWduZXQ8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNMjEuOTk5NDc1OSwxMC45NDI4MTgzIEwyMS45OTk5OTg1LDE2LjM3MTA0MTcgQzIyLDE2LjY4NzIwMDcgMjIsMTcuMDA1ODI3OCAyMiwxNy4zMjY5NDExIEMyMiwyMS41NjQ2NTQ1IDE4LjY0MjEzNTYsMjUgMTQuNSwyNSBDMTAuMzU3ODY0NCwyNSA3LDIxLjU2NDY1NDUgNywxNy4zMjY5NDExIEw3LjAwMDg3NTA4LDEwLjk5MDc1MDcgTDExLjAwMjI4MDgsMTAuOTk4NDEyNSBDMTEuMDAxNzAzMywxMS42OTgwMTE0IDExLjAwMTI0NywxMi40MTY4MjQ4IDExLjAwMDg5OTIsMTMuMTU1NDg4NyBMMTEsMTcuMzI2OTQxMSBDMTEsMTkuMzc1NjgwOSAxMi41ODc2ODQxLDIxIDE0LjUsMjEgQzE2LjQxMjMxNTksMjEgMTgsMTkuMzc1NjgwOSAxOCwxNy4zMjY5NDExIEMxOCwxNS4wNzAyMDMyIDE3Ljk5OTU2OTYsMTIuOTYxOTY2OCAxNy45OTg1MzksMTAuOTkxMDAzMiBMMjEuOTk5NDc1OSwxMC45NDI4MTgzIFogTTEwLDcgQzEwLjU1MjI4NDcsNyAxMSw3LjQ0NzcxNTI1IDExLDggTDExLDEwIEw3LDEwIEw3LDggQzcsNy40NDc3MTUyNSA3LjQ0NzcxNTI1LDcgOCw3IEwxMCw3IFogTTIxLDcgQzIxLjU1MjI4NDcsNyAyMiw3LjQ0NzcxNTI1IDIyLDggTDIyLDEwIEwxOCwxMCBMMTgsOCBDMTgsNy40NDc3MTUyNSAxOC40NDc3MTUzLDcgMTksNyBMMjEsNyBaIiBpZD0icGF0aC0xIj48L3BhdGg+CiAgICA8L2RlZnM+CiAgICA8ZyBpZD0iU3ltYm9scyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IkF0b21zL0ljb25zL1Rvb2xzL01hZ25ldCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTMuMDAwMDAwLCAtMy4wMDAwMDApIj4KICAgICAgICAgICAgPG1hc2sgaWQ9Im1hc2stMiIgZmlsbD0id2hpdGUiPgogICAgICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgPC9tYXNrPgogICAgICAgICAgICA8dXNlIGlkPSJNYXNrIiBmaWxsPSIjNUI1QjVCIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE0LjUwMDAwMCwgMTYuMDAwMDAwKSByb3RhdGUoNDUuMDAwMDAwKSB0cmFuc2xhdGUoLTE0LjUwMDAwMCwgLTE2LjAwMDAwMCkgIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==);
}
.leaflet-pm-toolbar .leaflet-pm-icon-rotate {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBpZD0icm90YXRlIiBkPSJNMjEuMiw1LjhjLTAuMS0wLjItMC4yLTAuMy0wLjMtMC41bC0wLjEtMC4yYy0wLjEtMC4yLTAuMi0wLjMtMC4zLTAuNWwtMC4xLTAuMmMtMC4xLTAuMi0wLjItMC4zLTAuNC0wLjVsLTAuMi0wLjNsMi44LTMuMUwxOCwwLjZsLTQuNiwwLjFsMC41LDQuNWwwLjUsNC41bDMuMi0zLjZ2MC4xbDAuMSwwLjJjMC4xLDAuMSwwLjEsMC4yLDAuMiwwLjJsMC4xLDAuMkMxOCw3LDE4LDcuMSwxOC4xLDcuMmMwLjMsMC43LDAuNiwxLjQsMC43LDIuMWMwLjIsMS40LDAsMi45LTAuNiw0LjJMMTgsMTMuOUwxNy45LDE0bC0wLjMsMC41bC0wLjEsMC4yYy0wLjIsMC4yLTAuNCwwLjUtMC42LDAuN2MtMC41LDAuNS0xLjEsMS0xLjcsMS4zYy0wLjYsMC40LTEuMywwLjYtMi4xLDAuOGMtMC43LDAuMS0xLjUsMC4yLTIuMiwwLjFjLTAuOC0wLjEtMS41LTAuMy0yLjItMC41Yy0wLjctMC4zLTEuMy0wLjctMS45LTEuMmwtMC40LTAuNGwtMC4yLTAuM0w2LDE1Yy0wLjEtMC4xLTAuMi0wLjItMC4yLTAuM2wtMC4zLTAuNGwtMC4xLTAuMWwtMC4yLTAuNGMwLTAuMS0wLjEtMC4xLTAuMS0wLjJsLTAuMy0wLjVsLTAuMS0wLjJjLTAuMS0wLjMtMC4yLTAuNi0wLjMtMC45Yy0wLjItMC44LTAuMy0xLjYtMC4zLTIuNGMwLTAuMiwwLTAuMywwLTAuNVY4LjljMC0wLjIsMC0wLjMsMC4xLTAuNGwwLjEtMC42bDAuMi0wLjZjMC4zLTAuOCwwLjctMS41LDEuMi0yLjJjMC41LTAuNywxLjEtMS4zLDEuOC0xLjhjMC4yLTAuMSwwLjMtMC40LDAuMS0wLjZDNy41LDIuNiw3LjQsMi41LDcuMywyLjVINy4xTDcsMi42QzYuMSwzLDUuNCwzLjYsNC43LDQuMkM0LDQuOSwzLjUsNS43LDMsNi42Yy0wLjksMS44LTEuMiwzLjgtMC44LDUuOGMwLjEsMC41LDAuMiwwLjksMC4zLDEuNGwwLjMsMC44QzIuOSwxNC43LDMsMTQuOCwzLDE1bDAuMiwwLjRjMCwwLjEsMC4xLDAuMiwwLjEsMC4ybDAuMywwLjVjMC4xLDAuMiwwLjIsMC4zLDAuMywwLjVsMC4xLDAuMmMwLjEsMC4xLDAuMiwwLjMsMC4zLDAuNEw1LDE3LjhjMC43LDAuNywxLjYsMS4zLDIuNSwxLjhjMC45LDAuNSwxLjksMC44LDMsMC45YzAuNSwwLjEsMSwwLjEsMS41LDAuMWMwLjYsMCwxLjEsMCwxLjYtMC4xYzEtMC4yLDIuMS0wLjUsMy0xbDAuMi0wLjFjMC4yLTAuMSwwLjMtMC4yLDAuNS0wLjNsMC43LTAuNGMwLjItMC4xLDAuMy0wLjIsMC40LTAuM2wwLjItMC4yYzAuMi0wLjEsMC40LTAuMywwLjUtMC41bDAuMS0wLjFjMC4zLTAuMywwLjctMC43LDAuOS0xbDAuNi0wLjlsMC40LTAuNmMxLTEuOSwxLjQtNC4xLDEuMS02LjJDMjIsNy44LDIxLjcsNi43LDIxLjIsNS44eiIvPgogICAgPC9kZWZzPgogICAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDIpIj4KICAgICAgICA8bWFzayBpZD0icm90YXRlLWIiIGZpbGw9IiNmZmYiPgogICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNyb3RhdGUiLz4KICAgICAgICA8L21hc2s+CiAgICAgICAgPHVzZSBmaWxsPSIjNUI1QjVCIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHhsaW5rOmhyZWY9IiNyb3RhdGUiLz4KICAgICAgICA8ZyBmaWxsPSIjNUI1QjVCIiBtYXNrPSJ1cmwoI3JvdGF0ZS1iKSI+CiAgICAgICAgICAgIDxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIzMCIvPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+Cg==);
}
.leaflet-pm-toolbar .leaflet-pm-icon-text {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOm5vbmU7c3Ryb2tlOiM1YjViNWI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS13aWR0aDoyLjVweDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPlRleHQ8L3RpdGxlPjxnIGlkPSJFYmVuZV8yIiBkYXRhLW5hbWU9IkViZW5lIDIiPjxwb2x5bGluZSBjbGFzcz0iY2xzLTEiIHBvaW50cz0iMTkuNjQgNy4yNyAxOS42NCA0IDEyIDQgMTIgMjAgMTUuOTEgMjAgOC4wOSAyMCAxMiAyMCAxMiA0IDQuMzYgNCA0LjM2IDcuMjciLz48L2c+PC9zdmc+);
}
.leaflet-buttons-control-button:hover,
.leaflet-buttons-control-button:focus {
cursor: pointer;
background-color: #f4f4f4;
}
.active > .leaflet-buttons-control-button {
box-shadow: inset 0 -1px 5px 2px rgba(81, 77, 77, 0.31);
}
.leaflet-buttons-control-text-hide {
display: none;
}
.button-container {
position: relative;
}
.button-container .leaflet-pm-actions-container {
z-index: 2;
position: absolute;
top: 0;
left: 100%;
display: none;
white-space: nowrap;
direction: ltr;
}
.leaflet-right
.leaflet-pm-toolbar
.button-container
.leaflet-pm-actions-container {
right: 100%;
left: auto;
}
.button-container.active .leaflet-pm-actions-container {
display: block;
}
.button-container
.leaflet-pm-actions-container:not(.pos-right)
a.leaflet-pm-action:last-child {
border-radius: 0 3px 3px 0;
border-right: 0;
}
.button-container
.leaflet-pm-actions-container.pos-right
a.leaflet-pm-action:first-child {
border-radius: 3px 0 0 3px;
}
.button-container
.leaflet-pm-actions-container.pos-right
a.leaflet-pm-action:last-child {
border-right: 0;
}
.button-container .leaflet-pm-actions-container .leaflet-pm-action {
padding: 0 10px;
background-color: #666;
color: #fff;
display: inline-block;
width: auto;
border-right: 1px solid #eee;
user-select: none;
border-bottom: none;
height: 29px;
line-height: 29px;
}
.leaflet-pm-toolbar
.button-container:first-child.pos-right.active
a.leaflet-buttons-control-button {
border-top-left-radius: 0;
}
.leaflet-pm-toolbar
.button-container:first-child.active:not(.pos-right)
a.leaflet-buttons-control-button {
border-top-right-radius: 0;
}
.button-container .leaflet-pm-actions-container .leaflet-pm-action:hover,
.button-container .leaflet-pm-actions-container .leaflet-pm-action:focus {
cursor: pointer;
background-color: #777;
}
/* That the active control is always over the other controls */
.leaflet-pm-toolbar.activeChild {
z-index: 801;
}
.leaflet-buttons-control-button.pm-disabled {
background-color: #f4f4f4;
}
.leaflet-buttons-control-button.pm-disabled > .control-icon {
filter: opacity(0.6);
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

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

View File

@@ -0,0 +1,666 @@
/* required styles */
.leaflet-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-container,
.leaflet-pane > svg,
.leaflet-pane > canvas,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
position: absolute;
left: 0;
top: 0;
}
.leaflet-container {
overflow: hidden;
}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
/* Prevents IE11 from highlighting tiles in blue */
.leaflet-tile::selection {
background: transparent;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast;
}
/* hack that prevents hw layers "stretching" when loading new tiles */
.leaflet-safari .leaflet-tile-container {
width: 1600px;
height: 1600px;
-webkit-transform-origin: 0 0;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg {
max-width: none !important;
max-height: none !important;
}
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer,
.leaflet-container .leaflet-tile {
max-width: none !important;
max-height: none !important;
width: auto;
padding: 0;
}
.leaflet-container img.leaflet-tile {
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
mix-blend-mode: plus-lighter;
}
.leaflet-container.leaflet-touch-zoom {
-ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y;
}
.leaflet-container.leaflet-touch-drag {
-ms-touch-action: pinch-zoom;
/* Fallback for FF which doesn't support pinch-zoom */
touch-action: none;
touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
-ms-touch-action: none;
touch-action: none;
}
.leaflet-container {
-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
width: 0;
height: 0;
-moz-box-sizing: border-box;
box-sizing: border-box;
z-index: 800;
}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
-moz-user-select: none;
}
.leaflet-pane { z-index: 400; }
.leaflet-tile-pane { z-index: 200; }
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane { z-index: 500; }
.leaflet-marker-pane { z-index: 600; }
.leaflet-tooltip-pane { z-index: 650; }
.leaflet-popup-pane { z-index: 700; }
.leaflet-map-pane canvas { z-index: 100; }
.leaflet-map-pane svg { z-index: 200; }
.leaflet-vml-shape {
width: 1px;
height: 1px;
}
.lvml {
behavior: url(#default#VML);
display: inline-block;
position: absolute;
}
/* control positioning */
.leaflet-control {
position: relative;
z-index: 800;
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
.leaflet-top,
.leaflet-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
float: left;
clear: both;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
/* zoom and fade animations */
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-animated {
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
}
svg.leaflet-zoom-animated {
will-change: transform;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
-webkit-transition: none;
-moz-transition: none;
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
/* cursors */
.leaflet-interactive {
cursor: pointer;
}
.leaflet-grab {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
cursor: crosshair;
}
.leaflet-popup-pane,
.leaflet-control {
cursor: auto;
}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
/* marker & overlays interactivity */
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-image-layer,
.leaflet-pane > svg path,
.leaflet-tile-container {
pointer-events: none;
}
.leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
/* visual tweaks */
.leaflet-container {
background: #ddd;
outline-offset: 1px;
}
.leaflet-container a {
color: #0078A8;
}
.leaflet-zoom-box {
border: 2px dotted #38f;
background: rgba(255,255,255,0.5);
}
/* general typography */
.leaflet-container {
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
font-size: 12px;
font-size: 0.75rem;
line-height: 1.5;
}
/* general toolbar styles */
.leaflet-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.leaflet-bar a {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.leaflet-bar a,
.leaflet-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.leaflet-bar a:hover,
.leaflet-bar a:focus {
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.leaflet-bar a.leaflet-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
.leaflet-touch .leaflet-bar a {
width: 30px;
height: 30px;
line-height: 30px;
}
.leaflet-touch .leaflet-bar a:first-child {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
.leaflet-touch .leaflet-bar a:last-child {
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
/* zoom control */
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
font: bold 18px 'Lucida Console', Monaco, monospace;
text-indent: 1px;
}
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
font-size: 22px;
}
/* layers control */
.leaflet-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.leaflet-control-layers-toggle {
background-image: url(images/layers.png);
width: 36px;
height: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(images/layers-2x.png);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
width: 44px;
height: 44px;
}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
display: none;
}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
display: block;
position: relative;
}
.leaflet-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.leaflet-control-layers-scrollbar {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 5px;
}
.leaflet-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.leaflet-control-layers label {
display: block;
font-size: 13px;
font-size: 1.08333em;
}
.leaflet-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}
/* Default icon URLs */
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
background-image: url(images/marker-icon.png);
}
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.8);
margin: 0;
}
.leaflet-control-attribution,
.leaflet-control-scale-line {
padding: 0 5px;
color: #333;
line-height: 1.4;
}
.leaflet-control-attribution a {
text-decoration: none;
}
.leaflet-control-attribution a:hover,
.leaflet-control-attribution a:focus {
text-decoration: underline;
}
.leaflet-attribution-flag {
display: inline !important;
vertical-align: baseline !important;
width: 1em;
height: 0.6669em;
}
.leaflet-left .leaflet-control-scale {
margin-left: 5px;
}
.leaflet-bottom .leaflet-control-scale {
margin-bottom: 5px;
}
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
line-height: 1.1;
padding: 2px 5px 1px;
white-space: nowrap;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.8);
text-shadow: 1px 1px #fff;
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
box-shadow: none;
}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* popup */
.leaflet-popup {
position: absolute;
text-align: center;
margin-bottom: 20px;
}
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
border-radius: 12px;
}
.leaflet-popup-content {
margin: 13px 24px 13px 20px;
line-height: 1.3;
font-size: 13px;
font-size: 1.08333em;
min-height: 1px;
}
.leaflet-popup-content p {
margin: 17px 0;
margin: 1.3em 0;
}
.leaflet-popup-tip-container {
width: 40px;
height: 20px;
position: absolute;
left: 50%;
margin-top: -1px;
margin-left: -20px;
overflow: hidden;
pointer-events: none;
}
.leaflet-popup-tip {
width: 17px;
height: 17px;
padding: 1px;
margin: -10px auto 0;
pointer-events: auto;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: white;
color: #333;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: 0;
right: 0;
border: none;
text-align: center;
width: 24px;
height: 24px;
font: 16px/24px Tahoma, Verdana, sans-serif;
color: #757575;
text-decoration: none;
background: transparent;
}
.leaflet-container a.leaflet-popup-close-button:hover,
.leaflet-container a.leaflet-popup-close-button:focus {
color: #585858;
}
.leaflet-popup-scrolled {
overflow: auto;
}
.leaflet-oldie .leaflet-popup-content-wrapper {
-ms-zoom: 1;
}
.leaflet-oldie .leaflet-popup-tip {
width: 24px;
margin: 0 auto;
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
}
.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
border: 1px solid #999;
}
/* div icon */
.leaflet-div-icon {
background: #4CAF50;
border: 1px solid #666;
width: 7px !important;
height: 7px !important;
margin-left: -5.5px !important;
margin-top: -5.5px !important;
border-radius: 10px;
}
/* Tooltip */
/* Base styles for the element that has a tooltip */
.leaflet-tooltip {
position: absolute;
padding: 6px;
background-color: #fff;
border: 1px solid #fff;
border-radius: 3px;
color: #222;
white-space: nowrap;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.leaflet-tooltip.leaflet-interactive {
cursor: pointer;
pointer-events: auto;
}
.leaflet-tooltip-top:before,
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
position: absolute;
pointer-events: none;
border: 6px solid transparent;
background: transparent;
content: "";
}
/* Directions */
.leaflet-tooltip-bottom {
margin-top: 6px;
}
.leaflet-tooltip-top {
margin-top: -6px;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-top:before {
left: 50%;
margin-left: -6px;
}
.leaflet-tooltip-top:before {
bottom: 0;
margin-bottom: -12px;
border-top-color: #fff;
}
.leaflet-tooltip-bottom:before {
top: 0;
margin-top: -12px;
margin-left: -6px;
border-bottom-color: #fff;
}
.leaflet-tooltip-left {
margin-left: -6px;
}
.leaflet-tooltip-right {
margin-left: 6px;
}
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
top: 50%;
margin-top: -6px;
}
.leaflet-tooltip-left:before {
right: 0;
margin-right: -12px;
border-left-color: #fff;
}
.leaflet-tooltip-right:before {
left: 0;
margin-left: -12px;
border-right-color: #fff;
}
/* Printing */
@media print {
/* Prevent printers from removing background-images of controls. */
.leaflet-control {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
function makeid(length) {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
counter += 1;
}
return result;
}

1
web/lib/components/qrcode.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,40 @@
// Скрипт перезагрузки страници свайпом.
let app_scroll = false;
let animID = document.getElementById('swipe_updater');
let animIconID = document.getElementById('swipe_icon');
window.addEventListener('scroll', function(e) {
if (window.matchMedia('(display-mode: standalone)').matches) {
let a = window.scrollY;
let b = 50;
let c = 125;
a = -a;
a = a;
animIconID.style.top = a/1.5;
console.log(window.scrollY);
if(window.scrollY <= -10){
animID.style.zIndex = 115;
} else {
animID.style.zIndex = 0;
}
if(window.scrollY <= -120){
if(app_scroll == false){
app_scroll = true;
animIconID.style.transform = 'rotate(180deg)';
animIconID.setAttribute('data-state', '')
}
} else if(window.scrollY >= 0){
if(app_scroll == true){
appReload();
app_scroll = false;
animIconID.style.transform = 'rotate(0deg)';
animIconID.setAttribute('data-state', 'active')
}
}
}
});

88
web/lib/components/turf.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,175 @@
<style>
*[disabled] {
opacity: 0.5;
}
select {
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
/* Arrow */
appearance: none;
background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%237a899d%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: right 0.3rem top 50%;
background-size: 0.55rem auto;
}
#header {
display: flex;
justify-content: space-around;
}
#header p {
font-size: 20px;
}
#list {
display: flex;
flex-direction: column;
align-items: center;
}
details {
color: var(--ColorThemes3);
width: 100%;
min-width: 320px;
background: var(--ColorThemes1);
margin: 20px 0px;
border-radius: 10px;
overflow: hidden;
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.04), 0px 0px 2px rgba(0, 0, 0, 0.04),
0px 0px 1px rgba(0, 0, 0, 0.04);
}
@media (min-width: 900px) {
#list {
align-items: flex-start;
justify-content: space-between;
flex-direction: row;
flex-wrap: wrap;
}
details {
width: calc(50% - 10px);
}
}
details[disabled] summary,
details.disabled summary {
pointer-events: none;
user-select: none;
}
details summary::-webkit-details-marker,
details summary::marker {
display: none;
content: "";
}
summary {
cursor: pointer;
background: #7a8a9d;
background: var(--PrimaryColor);
color: var(--PrimaryColorText);
height: 45px;
font-weight: 500;
display: flex;
align-items: center;
justify-content: space-between;
}
summary p {
padding: 0 10px;
color: var(--PrimaryColorText);
font-size: 14px;
font-weight: 500;
}
summary svg {
width: 25px;
height: 25px;
padding: 0 10px;
fill: var(--PrimaryColorText);
}
.apartments_list {
padding: 10px;
border-bottom: 2px solid var(--PrimaryColor);
border-left: 2px solid var(--PrimaryColor);
border-right: 2px solid var(--PrimaryColor);
border-radius: 0 0 10px 10px;
}
@media (max-width: 500px) {
.apartments_list {
padding: 1px;
}
}
.apartments_list > div {
display: flex;
font-size: 14px;
border-radius: 8px;
margin: 10px 10px 15px 10px;
flex-direction: column;
align-items: stretch;
border: 1px solid var(--ColorThemes3);
background: var(--ColorThemes2);
}
.apartments_list > div > .info {
display: flex;
font-size: 14px;
align-items: center;
justify-content: space-between;
border-radius: 8px;
}
.apartments_list > div > .info > span {
min-width: 40px;
font-size: 12px;
position: relative;
margin: 5px;
}
.apartments_list > div > .info > select {
color: #3d3d3d;
border-radius: 6px;
border: 1px solid #eaebef;
margin: 5px;
background-color: var(--ColorThemes3);
min-width: 110px;
width: 100%;
padding: 4px 20px 4px 4px;
height: 30px;
}
.apartments_list > div > .info > input {
color: #3d3d3d;
border-radius: 6px;
border: 1px solid #eaebef;
margin: 5px;
background-color: var(--ColorThemes3);
background-color: var(--ColorThemes0);
border: 1px solid var(--ColorThemes1);
color: var(--ColorThemes3);
width: 100%;
min-width: 70px;
padding: 0 4px;
height: calc(30px - 2px);
appearance: none;
-webkit-appearance: none;
}
.apartments_list > div > textarea {
border-radius: 6px;
font-size: 14px;
margin: 5px;
background-color: var(--ColorThemes0);
border: 1px solid var(--ColorThemes1);
color: var(--ColorThemes3);
width: calc(100% - 22px);
min-width: 70px;
padding: 5px;
min-height: 40px;
appearance: none;
resize: vertical;
-webkit-appearance: none;
}
</style>
<div class="page-card">
<div id="header">
<p id="status"></p>
<p id="hash"></p>
</div>
<div id="list"></div>
</div>

View File

@@ -0,0 +1,358 @@
let socket, username;
let listEntrances = []
let listApartment = []
let holdTimer;
let startTime;
const Card = {
init: async (type, id) => {
let html = await fetch('/lib/pages/card/index.html').then((response) => response.text());
app.innerHTML = html;
house = id;
if (socket) socket.close(1000, "Перезапуск соединения");
if (type == "house") {
getEntrances();
start(makeid(6));
}
document.addEventListener("mousedown", handleStart);
document.addEventListener("touchstart", handleStart);
document.addEventListener("mouseup", handleCancel);
document.addEventListener("mouseleave", handleCancel);
document.addEventListener("touchend", handleCancel);
document.addEventListener("touchcancel", handleCancel);
function handleStart(event) {
const button = event.target.closest(".hold-button");
if (!button) return;
// event.preventDefault();
startTime = Date.now();
holdTimer = setTimeout(() => {
console.log("Долгое нажатие на", button.name);
let number_id = button.name.split("-");
mess(Number(number_id[0]), Number(number_id[1]));
}, 1000);
}
function handleCancel() {
const holdDuration = Date.now() - startTime; // Считаем, сколько длилось нажатие
if (holdDuration < 1000) {
clearTimeout(holdTimer); // Если нажали менее 1 секунды, сбрасываем таймер
}
}
}
}
// let color_status = [
// "#000000",
// "#C16917",
// "#b10202",
// "#3d3d3d",
// "#11734b",
// "#6cc5fc",
// "#5a3286"
// ];
// let color_status = [
// ["#ffffff", "#000000"],
// ["#e7af32", "#ffffff"],
// ["#fc2a2a", "#ffffff"],
// ["#3d3d3d", "#ffffff"],
// ["#11a568", "#ffffff"],
// ["#6cc5fc", "#ffffff"],
// ["#b381eb", "#ffffff"]
// ];
let color_status = [
["var(--ColorThemes2)", "var(--ColorThemes3)"],
["#fbf1e0", "#ff8300"],
["#fce3e2", "#ff0000"],
["#d7ddec", "#2919bd"],
["#d5e9dd", "#11a568"],
["#d7ebfa", "#3fb4fc"],
["#e8dbf5", "#b381eb"]
];
function start(name) {
if (!name) return;
document.getElementById("hash").innerText = `HASH: ${name}`
username = name;
let uuid = localStorage.getItem("uuid");
socket = new WebSocket(`${CONFIG.wss}?uuid=${uuid}`);
socket.onopen = function (e) {
console.log("[WebSocket | open] Соединение установлено");
document.getElementById("status").innerText = "WebSocket | open";
const message = {
event: 'connection',
id: getTimeInSeconds(),
date: getTimeInSeconds(),
uuid: uuid,
username: name,
data: {
id: 1,
entrance_id: 1,
apartment_number: 1,
title: "1",
group_number: 1,
status: 1,
description: "",
created_at: 1727541827,
updated_at: 1727541827
}
}
socket.send(JSON.stringify(message))
};
socket.onmessage = function (event) {
let data = JSON.parse(event.data)
if (data.event == 'connection') {
if (data.username == username) return
console.log(`Добавлен новый пользователь по имени ${data.username}`);
} else if (data.event == 'message') {
update(data);
if (data.username == username) return
console.log(`${data.username} пишет: `, data.data);
}
};
socket.onclose = function (event) {
if (event.wasClean) {
document.getElementById("status").innerText = "WebSocket | close"
console.log(`[WebSocket | close] Соединение закрыто чисто, код=${event.code} причина=${event.reason}`);
} else {
document.getElementById("status").innerText = "WebSocket | close"
console.log('[WebSocket | close] Соединение прервано');
// setTimeout(function() {
// start(username);
// }, 1000);
const result = confirm(`З'єднання розірвано! Перепідключитись?`);
if (result) {
getEntrances();
start(username);
}
}
};
socket.onerror = function (error) {
console.log(`[WebSocket | error]`);
document.getElementById("status").innerText = "WebSocket | error"
};
}
function mess(entrance_number, id, date_type) {
let sort_mode = localStorage.getItem('sort_mode') ?? true;
console.log(id, listApartment[entrance_number]);
const pos = listApartment[entrance_number].map(e => e.id).indexOf(id);
let apartment = listApartment[entrance_number][pos];
console.log(pos, apartment);
let status = document.getElementById(`status_${id}`);
let description = document.getElementById(`description_${id}`);
let date = new Date(document.getElementById(`date_${id}`).value);
const timestamp = date.getTime();
apartment.description = description.value;
apartment.status = Number(status.value);
apartment.updated_at = date_type ? getTimeInSeconds(timestamp) : getTimeInSeconds(),
status.style.backgroundColor = color_status[status.value][0];
status.style.color = color_status[status.value][1];
status.style.border = `1px solid ${color_status[status.value][1]}`;
let user_hash = localStorage.getItem('hash');
let message = {
event: 'message',
id: getTimeInSeconds(),
date: getTimeInSeconds(),
hash: user_hash,
username: username,
data: {
id: apartment.id,
entrance_id: apartment.entrance_id,
apartment_number: apartment.apartment_number,
title: apartment.title,
group_number: apartment.group_number,
status: apartment.status,
description: apartment.description,
updated_at: apartment.updated_at,
}
}
socket.send(JSON.stringify(message));
if (!date_type && sort_mode != 'false') sort(apartment.id, apartment.entrance_id);
}
function update(message) {
if (!document.getElementById(`status_${message.data.id}`)) return;
let now = new Date(message.data.updated_at);
now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
document.getElementById(`card_${message.data.id}`).style.backgroundColor = color_status[message.data.status][0];
document.getElementById(`card_${message.data.id}`).style.color = color_status[message.data.status][1];
document.getElementById(`card_${message.data.id}`).style.border = `1px solid ${color_status[message.data.status][1]}`;
document.getElementById(`status_${message.data.id}`).style.backgroundColor = color_status[message.data.status][0];
document.getElementById(`status_${message.data.id}`).style.color = color_status[message.data.status][1];
document.getElementById(`status_${message.data.id}`).style.border = `1px solid ${color_status[message.data.status][1]}`;
document.getElementById(`status_${message.data.id}`).value = message.data.status;
document.getElementById(`description_${message.data.id}`).value = message.data.description;
document.getElementById(`date_${message.data.id}`).value = now.toISOString().slice(0, 16);
}
function getEntrances(house_id = house) {
const uuid = localStorage.getItem('uuid');
const URL = `${CONFIG.api}/house/${house_id}/entrances`;
fetch(URL, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
})
.then(function (response) {
return response.json();
})
.then(function (data) {
listEntrances = data;
document.getElementById('list').innerHTML = "";
for (let i = 0; i < listEntrances.length; i++) {
const element = listEntrances[i];
let status = () => {
if ((element.history.name == "Групова" || element.history.name == USER.name) && element.working) return "open";
else if (USER.administrator.uuid || (USER.moderator.uuid && USER.moderator.can_manager_territory)) return "close";
return "style='display: none;'"
}
let statusIcon = () => {
if ((element.history.name == "Групова" || element.history.name == USER.name) && element.working) return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M 12 1 C 9.1277778 1 6.7189086 3.0461453 6.1230469 5.7871094 L 8.078125 6.2128906 C 8.4822632 4.3538547 10.072222 3 12 3 C 14.27619 3 16 4.7238095 16 7 L 16 8 L 6 8 C 4.9069372 8 4 8.9069372 4 10 L 4 20 C 4 21.093063 4.9069372 22 6 22 L 18 22 C 19.093063 22 20 21.093063 20 20 L 20 10 C 20 8.9069372 19.093063 8 18 8 L 18 7 C 18 3.6761905 15.32381 1 12 1 z M 6 10 L 18 10 L 18 20 L 6 20 L 6 10 z M 12 13 C 10.9 13 10 13.9 10 15 C 10 16.1 10.9 17 12 17 C 13.1 17 14 16.1 14 15 C 14 13.9 13.1 13 12 13 z"/></svg>'
else return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M 12 1 C 8.6761905 1 6 3.6761905 6 7 L 6 8 C 4.9069372 8 4 8.9069372 4 10 L 4 20 C 4 21.093063 4.9069372 22 6 22 L 18 22 C 19.093063 22 20 21.093063 20 20 L 20 10 C 20 8.9069372 19.093063 8 18 8 L 18 7 C 18 3.6761905 15.32381 1 12 1 z M 12 3 C 14.27619 3 16 4.7238095 16 7 L 16 8 L 8 8 L 8 7 C 8 4.7238095 9.7238095 3 12 3 z M 6 10 L 18 10 L 18 20 L 6 20 L 6 10 z M 12 13 C 10.9 13 10 13.9 10 15 C 10 16.1 10.9 17 12 17 C 13.1 17 14 16.1 14 15 C 14 13.9 13.1 13 12 13 z"/></svg>'
}
document.getElementById('list').innerHTML += `
<details ${status()}>
<summary>
<p>${element.title}</p>
${statusIcon()}
</summary>
<div id="apartments_${element.id}" class="apartments_list">
</div>
</details>
`;
getApartment(element.id, element.entrance_number);
console.log(element);
}
})
}
function getApartment(entrance_id, entrance_number) {
const uuid = localStorage.getItem('uuid');
const URL = `${CONFIG.api}/apartment/${entrance_id}`;
fetch(URL, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
})
.then(function (response) {
return response.json();
})
.then(function (data) {
listApartment[entrance_number] = data;
data.sort((a, b) => a.apartment_number - b.apartment_number);
data.sort((a, b) => a.updated_at - b.updated_at);
for (let i = 0; i < data.length; i++) {
const element = data[i];
let now = new Date(element.updated_at);
now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
now = now.toISOString().slice(0, 16)
let disabled = () => {
if (USER.administrator.uuid || (USER.moderator.uuid && USER.moderator.can_manager_territory)) return '';
else if (element.status == 2) return "disabled";
}
document.getElementById(`apartments_${entrance_id}`).innerHTML += `
<div id="card_${element.id}" style="border: 1px solid ${color_status[element.status][1]};background: ${color_status[element.status][0]};color: ${color_status[element.status][1]};">
<div class="info">
<span>кв.${element.title}</span>
<select id="status_${element.id}" onchange="mess(${entrance_number}, ${element.id})" style="background-color: ${color_status[element.status][0]}; color: ${color_status[element.status][1]}; border: 1px solid ${color_status[element.status][1]};" ${disabled()}>
<option value="0" ${element.status == 0 ? "selected" : ""}></option>
<option value="1" ${element.status == 1 ? "selected" : ""}>Відмова</option>
<option value="2" ${element.status == 2 ? "selected" : ""}>Не заходити (Груба відмова)</option>
<option value="3" ${element.status == 3 ? "selected" : ""}>Нема домофона</option>
<option value="4" ${element.status == 4 ? "selected" : ""}>Повторна відвідина</option>
<option value="5" ${element.status == 5 ? "selected" : ""}>Немає вдома</option>
<option value="6" ${element.status == 6 ? "selected" : ""}>Свідки Єгови</option>
</select>
<input onchange="mess(${entrance_number}, ${element.id}, true)" name="${entrance_number}-${element.id}" class="hold-button" type="datetime-local" id="date_${element.id}" placeholder="Дата" value="${element.updated_at ? now : ""}" ${disabled()} style="max-width: 170px;">
</div>
<textarea onchange="mess(${entrance_number}, ${element.id}, true)" id="description_${element.id}" placeholder="Нотатки..." ${disabled()}}>${element.description ?? ""}</textarea>
</div>
`;
}
})
}
function sort(id, entrance_id) {
let child = document.getElementById(`card_${id}`);
document.getElementById(`apartments_${entrance_id}`).removeChild(child);
document.getElementById(`apartments_${entrance_id}`).append(child);
child.style.border = "1px solid var(--PrimaryColor)";
}
function getTimeInSeconds(time = Date.now()) {
// Если время больше 10 знаков (это значит, что время в миллисекундах)
if (time.toString().length < 10) {
// Округляем до секунд, убирая последние 3 цифры (миллисекунды)
time = Math.floor(time * 1000);
}
return time;
}

View File

@@ -0,0 +1,6 @@
.page-card {
width: calc(100% - 40px);
display: flex;
flex-direction: column;
margin: 20px 20px 0 20px;
}

View File

@@ -0,0 +1,192 @@
<div class="page-constructor">
<details id="details-info" open>
<summary>
<span>Крок 1.</span> Інформація про будинок, територію, точки на карті
</summary>
<form id="info-form">
<div id="details-info-type">
<div class="tabs">
<input
type="radio"
id="info-type-house"
value="house"
name="info-type"
checked
/>
<label class="tab" for="info-type-house">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<path
d="M 14.5 6 A 1.50015 1.50015 0 0 0 13 7.5 L 13 25 L 7.5 25 A 1.50015 1.50015 0 0 0 6 26.5 L 6 42.5 A 1.50015 1.50015 0 1 0 9 42.5 L 9 28 L 14.253906 28 A 1.50015 1.50015 0 0 0 14.740234 28 L 19 28 L 19 42.5 A 1.50015 1.50015 0 1 0 22 42.5 L 22 26.746094 A 1.50015 1.50015 0 0 0 22 26.259766 L 22 22 L 33.253906 22 A 1.50015 1.50015 0 0 0 33.740234 22 L 39 22 L 39 42.5 A 1.50015 1.50015 0 1 0 42 42.5 L 42 20.5 A 1.50015 1.50015 0 0 0 40.5 19 L 35 19 L 35 7.5 A 1.50015 1.50015 0 0 0 33.5 6 L 14.5 6 z M 16 9 L 32 9 L 32 19 L 20.5 19 A 1.50015 1.50015 0 0 0 19 20.5 L 19 25 L 16 25 L 16 9 z M 20 12 C 19.448 12 19 12.448 19 13 L 19 15 C 19 15.552 19.448 16 20 16 L 22 16 C 22.552 16 23 15.552 23 15 L 23 13 C 23 12.448 22.552 12 22 12 L 20 12 z M 26 12 C 25.448 12 25 12.448 25 13 L 25 15 C 25 15.552 25.448 16 26 16 L 28 16 C 28.552 16 29 15.552 29 15 L 29 13 C 29 12.448 28.552 12 28 12 L 26 12 z M 26 25 C 25.448 25 25 25.448 25 26 L 25 28 C 25 28.552 25.448 29 26 29 L 28 29 C 28.552 29 29 28.552 29 28 L 29 26 C 29 25.448 28.552 25 28 25 L 26 25 z M 33 25 C 32.448 25 32 25.448 32 26 L 32 28 C 32 28.552 32.448 29 33 29 L 35 29 C 35.552 29 36 28.552 36 28 L 36 26 C 36 25.448 35.552 25 35 25 L 33 25 z M 13 31 C 12.448 31 12 31.448 12 32 L 12 34 C 12 34.552 12.448 35 13 35 L 15 35 C 15.552 35 16 34.552 16 34 L 16 32 C 16 31.448 15.552 31 15 31 L 13 31 z M 26 31 C 25.448 31 25 31.448 25 32 L 25 34 C 25 34.552 25.448 35 26 35 L 28 35 C 28.552 35 29 34.552 29 34 L 29 32 C 29 31.448 28.552 31 28 31 L 26 31 z M 33 31 C 32.448 31 32 31.448 32 32 L 32 34 C 32 34.552 32.448 35 33 35 L 35 35 C 35.552 35 36 34.552 36 34 L 36 32 C 36 31.448 35.552 31 35 31 L 33 31 z M 13 37 C 12.448 37 12 37.448 12 38 L 12 40 C 12 40.552 12.448 41 13 41 L 15 41 C 15.552 41 16 40.552 16 40 L 16 38 C 16 37.448 15.552 37 15 37 L 13 37 z M 26 37 C 25.448 37 25 37.448 25 38 L 25 40 C 25 40.552 25.448 41 26 41 L 28 41 C 28.552 41 29 40.552 29 40 L 29 38 C 29 37.448 28.552 37 28 37 L 26 37 z M 33 37 C 32.448 37 32 37.448 32 38 L 32 40 C 32 40.552 32.448 41 33 41 L 35 41 C 35.552 41 36 40.552 36 40 L 36 38 C 36 37.448 35.552 37 35 37 L 33 37 z"
/>
</svg>
<span>Багатоквартирний будинок</span>
</label>
<input
type="radio"
id="info-type-homestead"
value="homestead"
name="info-type"
/>
<label class="tab" for="info-type-homestead">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<path
d="M 24 5.015625 C 22.851301 5.015625 21.70304 5.3892757 20.753906 6.1367188 A 1.50015 1.50015 0 0 0 20.751953 6.1367188 L 8.859375 15.509766 C 7.0558128 16.931133 6 19.102989 6 21.400391 L 6 39.488281 C 6 41.403236 7.5850452 42.988281 9.5 42.988281 L 38.5 42.988281 C 40.414955 42.988281 42 41.403236 42 39.488281 L 42 21.400391 C 42 19.102989 40.944187 16.931133 39.140625 15.509766 L 39 15.396484 L 39 7.5 A 1.50015 1.50015 0 0 0 37.5 6 L 32.5 6 A 1.50015 1.50015 0 0 0 31 7.5 L 31 9.09375 L 27.246094 6.1367188 C 26.29696 5.3892758 25.148699 5.015625 24 5.015625 z M 24 8.0078125 C 24.489801 8.0078125 24.979759 8.1705836 25.390625 8.4941406 L 31.572266 13.363281 A 1.50015 1.50015 0 0 0 34 12.185547 L 34 9 L 36 9 L 36 16.125 A 1.50015 1.50015 0 0 0 36.572266 17.302734 L 37.285156 17.865234 C 38.369594 18.719867 39 20.019792 39 21.400391 L 39 39.488281 C 39 39.783326 38.795045 39.988281 38.5 39.988281 L 9.5 39.988281 C 9.2049548 39.988281 9 39.783326 9 39.488281 L 9 21.400391 C 9 20.019792 9.6304058 18.719867 10.714844 17.865234 L 22.609375 8.4941406 C 23.020241 8.1705836 23.510199 8.0078125 24 8.0078125 z M 14.5 23.988281 A 1.50015 1.50015 0 0 0 13 25.488281 L 13 33.488281 A 1.50015 1.50015 0 0 0 14.5 34.988281 L 20.5 34.988281 A 1.50015 1.50015 0 0 0 22 33.488281 L 22 25.488281 A 1.50015 1.50015 0 0 0 20.5 23.988281 L 14.5 23.988281 z M 27.5 23.988281 A 1.50015 1.50015 0 0 0 26 25.488281 L 26 33.488281 A 1.50015 1.50015 0 0 0 27.5 34.988281 L 33.5 34.988281 A 1.50015 1.50015 0 0 0 35 33.488281 L 35 25.488281 A 1.50015 1.50015 0 0 0 33.5 23.988281 L 27.5 23.988281 z M 16 26.988281 L 19 26.988281 L 19 31.988281 L 16 31.988281 L 16 26.988281 z M 29 26.988281 L 32 26.988281 L 32 31.988281 L 29 31.988281 L 29 26.988281 z"
/>
</svg>
<span>Житловий район</span>
</label>
<input
type="radio"
id="info-type-points"
value="points"
name="info-type"
/>
<label class="tab" for="info-type-points">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<path
d="M 24 4 C 16.285455 4 10 10.285455 10 18 C 10 21.46372 11.272608 24.643548 13.359375 27.085938 L 13.359375 27.087891 L 13.361328 27.087891 C 13.361328 27.087891 19.149094 33.866566 21.298828 35.917969 C 22.798087 37.348278 25.199464 37.347492 26.699219 35.917969 C 29.129083 33.600994 34.636721 27.090553 34.640625 27.085938 L 34.642578 27.082031 C 36.728766 24.639939 38 21.462159 38 18 C 38 10.285455 31.714545 4 24 4 z M 24 7 C 30.093455 7 35 11.906545 35 18 C 35 20.73228 34.005417 23.211194 32.359375 25.136719 L 32.359375 25.138672 L 32.357422 25.138672 C 32.357422 25.138672 26.632181 31.83589 24.628906 33.746094 C 24.258577 34.099392 23.73947 34.099392 23.369141 33.746094 C 21.715477 32.16807 15.643092 25.141834 15.638672 25.136719 L 15.636719 25.132812 C 13.99327 23.20762 13 20.730712 13 18 C 13 11.906545 17.906545 7 24 7 z M 24 12 C 22.125 12 20.528815 12.757133 19.503906 13.910156 C 18.478997 15.063179 18 16.541667 18 18 C 18 19.458333 18.478997 20.936821 19.503906 22.089844 C 20.528815 23.242867 22.125 24 24 24 C 25.875 24 27.471185 23.242867 28.496094 22.089844 C 29.521003 20.936821 30 19.458333 30 18 C 30 16.541667 29.521003 15.063179 28.496094 13.910156 C 27.471185 12.757133 25.875 12 24 12 z M 24 15 C 25.124999 15 25.778816 15.367867 26.253906 15.902344 C 26.728997 16.436821 27 17.208333 27 18 C 27 18.791667 26.728997 19.563179 26.253906 20.097656 C 25.778816 20.632133 25.124999 21 24 21 C 22.875001 21 22.221184 20.632133 21.746094 20.097656 C 21.271003 19.563179 21 18.791667 21 18 C 21 17.208333 21.271003 16.436821 21.746094 15.902344 C 22.221184 15.367867 22.875001 15 24 15 z M 12.771484 29.441406 C 8.2264844 30.754406 5 32.953 5 36 C 5 41.252 14.558 44 24 44 C 33.442 44 43 41.252 43 36 C 43 32.954 39.775422 30.757359 35.232422 29.443359 C 34.654422 30.099359 33.863187 30.993844 32.992188 31.964844 C 37.418188 33.005844 40 34.691 40 36 C 40 38.039 33.767 41 24 41 C 14.233 41 8 38.039 8 36 C 8 34.69 10.586531 33.001938 15.019531 31.960938 C 14.152531 30.995938 13.355484 30.100406 12.771484 29.441406 z"
/>
</svg>
<span>Точки на карті</span>
</label>
<span class="glider"></span>
</div>
</div>
<div id="details-info-address" class="details-info-input">
<label for="info-address-title">Назва вулиці</label>
<input
type="text"
id="info-address-title"
name="address"
required
value=""
/>
</div>
<div id="details-info-number" class="details-info-input">
<label for="info-number-title">Номер будинку</label>
<input
type="text"
id="info-number-title"
name="number"
required
value=""
/>
</div>
<div id="details-info-settlement" class="details-info-input">
<label for="info-settlement-title">Місто</label>
<input
type="text"
id="info-settlement-title"
name="settlement"
required
value="Тернопіль"
/>
</div>
<div id="details-info-group" class="details-info-input">
<label for="info-group-title">Теократична група</label>
<input
type="number"
id="info-group-title"
name="group"
required
value=""
/>
</div>
<div id="details-info-osm" class="details-info-input">
<label for="info-settlement-title">OSM iD</label>
<div>
<input
type="text"
id="info-osm-title"
name="osm"
placeholder="123, 345, 678"
required
value=""
/>
<a href="https://www.openstreetmap.org/#map=19/49.561725/25.604458" target="_blank" title="Де знайти OSM iD ?"
><svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 48 48"
width="100px"
height="100px"
>
<path
d="M 24 4 C 12.972066 4 4 12.972074 4 24 C 4 35.027926 12.972066 44 24 44 C 35.027934 44 44 35.027926 44 24 C 44 12.972074 35.027934 4 24 4 z M 24 7 C 33.406615 7 41 14.593391 41 24 C 41 33.406609 33.406615 41 24 41 C 14.593385 41 7 33.406609 7 24 C 7 14.593391 14.593385 7 24 7 z M 24 14 A 2 2 0 0 0 24 18 A 2 2 0 0 0 24 14 z M 23.976562 20.978516 A 1.50015 1.50015 0 0 0 22.5 22.5 L 22.5 33.5 A 1.50015 1.50015 0 1 0 25.5 33.5 L 25.5 22.5 A 1.50015 1.50015 0 0 0 23.976562 20.978516 z"
/></svg
></a>
</div>
</div>
<button id="info-form-button" type="submit">Далі</button>
</form>
</details>
<details id="details-map" disabled>
<summary id="details-map-title">
<span>Крок 2.</span> Створення підїздів
</summary>
<form id="map-form">
<div class="editor-buttons" id="details-map-buttons-entranse">
<button type="button" onclick="Constructor.editor.drawEntranse()">
Створити новий під'їзд
</button>
<div>
<button type="button" id="ruler" onclick="Constructor.editor.drawRectangle()">
Лінійка
</button>
<button
type="button"
id="ruler_divide"
onclick="Constructor.editor.ruler()"
style="display: none"
>
Поділити
</button>
</div>
</div>
<div
class="editor-buttons"
id="details-map-buttons-homestead"
style="display: none"
>
<div>
<button type="button" id="ruler" onclick="Constructor.editor.drawRectangle()">
Лінійка
</button>
<button
type="button"
id="ruler_divide"
onclick="Constructor.editor.ruler()"
style="display: none"
>
Поділити
</button>
</div>
</div>
<div id="list-entranse" style="display: none"></div>
<div id="list-homestead" style="display: none"></div>
<div class="block-map">
<div id="map"></div>
</div>
<button id="map-form-button" type="submit">Далі</button>
</form>
</details>
<details id="details-area" disabled>
<summary><span>Крок 3.</span> Конструктор квартир <input type="number" value="1" id="next-apartment-title" onchange="Constructor.apartments.editNum(this)" title="Авто-номер наступної квартири"></summary>
<form id="area-form">
<div id="list-area"></div>
<button id="area-form-button" type="submit">Зберегти</button>
</form>
</details>
</div>

View File

@@ -0,0 +1,731 @@
let map, houseGroup, entransePolygonsGroup, entranseNumPolygonsGroup, splitPolygonsGroup, RectangleGroup;
let numApartments = 1;
let mode = '';
const Constructor = {
info: {
type: null,
group_id: null,
title: null,
number: null,
points: [],
points_number: [],
point_icons: [],
geo: [],
osm_id: [],
settlement: [],
description: null,
entrance: [],
apartments: {},
zoom: null
},
init: async () => {
let html = await fetch('/lib/pages/constructor/index.html').then((response) => response.text());
app.innerHTML = html;
map = "";
map = "";
houseGroup = "";
entransePolygonsGroup = "";
entranseNumPolygonsGroup = "";
splitPolygonsGroup = "";
RectangleGroup = "";
numApartments = 1;
Constructor.apartments.init();
document.querySelectorAll('input[name="info-type"]').forEach(radio => {
radio.addEventListener('change', event => {
console.log(`Выбран: ${event.target.value}`);
Constructor.info.type = event.target.value;
let detailsInfo_number = document.getElementById('details-info-number');
let detailsInfo_osm = document.getElementById('details-info-osm');
let detailsInfo_number_title = document.getElementById('info-number-title');
let detailsInfo_osm_title = document.getElementById('info-osm-title');
let detailsMap_title = document.getElementById('details-map-title');
let detailsMap_buttons_entranse = document.getElementById('details-map-buttons-entranse');
let detailsMap_buttons_homestead = document.getElementById('details-map-buttons-homestead');
let detailsMap_button = document.getElementById('map-form-button');
let detailsArea = document.getElementById('details-area');
switch (event.target.value) {
case 'points':
detailsInfo_number.style.display = "none";
detailsInfo_osm.style.display = "none";
detailsInfo_number_title.removeAttribute("required");
detailsInfo_osm_title.removeAttribute("required");
detailsMap_title.innerHTML = "<span>Крок 2.</span> Створення точок на карті"
detailsMap_buttons_entranse.style.display = "none";
detailsMap_buttons_homestead.style.display = "none";
detailsMap_button.innerText = "Зберегти";
detailsArea.style.display = "none";
break;
case 'homestead':
detailsInfo_number.style.display = "";
detailsInfo_osm.style.display = "";
detailsInfo_number_title.setAttribute("required", "");
detailsInfo_osm_title.setAttribute("required", "");
detailsMap_title.innerHTML = "<span>Крок 2.</span> Створення житлових територій"
detailsMap_buttons_entranse.style.display = "none";
detailsMap_buttons_homestead.style.display = "";
detailsMap_button.innerText = "Зберегти";
detailsArea.style.display = "none";
break;
default:
detailsInfo_number.style.display = "";
detailsInfo_osm.style.display = "";
detailsInfo_number_title.setAttribute("required", "");
detailsInfo_osm_title.setAttribute("required", "");
detailsMap_title.innerHTML = "<span>Крок 2.</span> Створення підʼїздів"
detailsMap_buttons_entranse.style.display = "";
detailsMap_buttons_homestead.style.display = "none";
detailsMap_button.innerText = "Далі";
detailsArea.style.display = "";
break;
}
});
});
document.getElementById("info-form").addEventListener("submit", function (event) {
event.preventDefault();
let details_map = document.getElementById("details-map");
details_map.removeAttribute("disabled");
details_map.open = true;
const infoForm = document.getElementById("info-form");
let osm = () => {
const a = document.getElementById("info-osm-title").value;
const b = a.replace(/\s+/g, "").split(',')
return b;
}
Constructor.info.type = infoForm.querySelector('input[name="info-type"]:checked').value;
Constructor.info.title = document.getElementById("info-address-title").value;
Constructor.info.number = document.getElementById("info-number-title").value;
Constructor.info.settlement = document.getElementById("info-settlement-title").value;
Constructor.info.group_id = Number(document.getElementById("info-group-title").value);
Constructor.info.osm_id = osm();
Constructor.osm.init();
Constructor.osm.setMap();
})
document.getElementById("map-form").addEventListener("submit", async function (event) {
event.preventDefault();
let details_area = document.getElementById("details-area");
details_area.removeAttribute("disabled");
details_area.open = true;
switch (Constructor.info.type) {
case 'points':
break;
case 'homestead':
await Constructor.api.setPack();
break;
default:
let details_area = document.getElementById("details-area");
details_area.removeAttribute("disabled");
details_area.open = true;
break;
}
})
document.getElementById("area-form").addEventListener("submit", async function (event) {
event.preventDefault();
await Constructor.api.setPack();
})
},
apartments: {
init: () => {
let listArea = document.getElementById('list-area');
listArea.innerHTML = ``;
for (const key in Constructor.info.apartments) {
const element = Constructor.info.apartments[key];
const pos = Constructor.info.entrance.map(e => e.editor_id).indexOf(key);
console.log(element);
let listArea = document.getElementById('list-area');
listArea.innerHTML += `
<div class="block-area" id="block-area-${key}">
<h3>${Constructor.info.entrance[pos].title}</h3>
<button class="addFloors" title="Додати поверх" type="button" onclick="Constructor.apartments.addFloors('${key}')"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg></button>
<div id="area-${key}"></div>
</div>
`;
element.sort((a, b) => a.floors_number - b.floors_number);
let uniqueFloors = [...new Set(element.map(obj => obj.floors_number))];
for (let i = 0; i < uniqueFloors.length; i++) {
let num = uniqueFloors[i];
let areaBlock = document.getElementById(`area-${key}`);
let div = document.createElement('div');
div.className = "block-apartments-floors";
div.id = `floors-${key}-${num}`
div.innerHTML = `
<button class="addApartment" id="buttonApartment-${key}-${num}" title="Додати квартиру" type="button" onclick="Constructor.apartments.addApartment('${key}', '${num}')"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg></button>
`;
areaBlock.prepend(div);
}
element.sort((a, b) => b.title - a.title);
for (let i = 0; i < element.length; i++) {
const apartment = element[i];
let num = apartment.floors_number;
let floorsBlock = document.getElementById(`floors-${key}-${apartment.floors_number}`);
let div = document.createElement('div');
div.className = "block-apartments-number";
div.id = `block-apartments-${key}-${apartment.editor_id}`
div.innerHTML = `
<input type="text" value="${apartment.title}" id="apartament-${key}-${apartment.editor_id}" onchange="Constructor.apartments.editApartment('${key}','${apartment.editor_id}')">
<button type="button" onclick="Constructor.apartments.deleteApartment('${key}','${apartment.editor_id}')">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>
</button>
`;
floorsBlock.prepend(div);
}
element.sort((a, b) => b.floors_number - a.floors_number);
}
},
editNum: (element) => {
numApartments = Number(element.value);
},
addFloors: (area) => {
let areaBlock = document.getElementById(`area-${area}`);
let uniqueFloors = [...new Set(Constructor.info.apartments[area].map(obj => obj.floors_number))];
let new_floors = uniqueFloors.length + 1;
let new_id = makeid(5);
let div = document.createElement('div');
div.className = "block-apartments-floors";
div.id = `floors-${area}-${new_floors}`
div.innerHTML = `
<h2>Поверх ${new_floors}</h2>
<div class="block-apartments-number" id="block-apartments-${area}-${new_id}">
<input type="text" value="${numApartments}" id="apartament-${area}-${new_id}" onchange="Constructor.apartments.editApartment('${area}', '${new_id}')">
<button type="button" onclick="Constructor.apartments.deleteApartment('${area}', '${new_id}')">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>
</button>
</div>
<button class="addApartment" id="buttonApartment-${area}-${new_floors}" title="Додати квартиру" type="button" onclick="Constructor.apartments.addApartment('${area}', '${new_floors}')"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg></button>
`
areaBlock.prepend(div);
Constructor.info.apartments[area].push({
editor_id: new_id,
entrance_id: null,
apartment_number: Constructor.info.apartments[area].length,
title: numApartments,
floors_number: new_floors
});
numApartments++;
let next_apartment_title = document.getElementById('next-apartment-title');
next_apartment_title.value = numApartments;
},
addApartment: (area, floors) => {
let new_id = makeid(5);
Constructor.info.apartments[area].push({
editor_id: new_id,
entrance_id: null,
apartment_number: Constructor.info.apartments[area].length,
title: numApartments,
floors_number: Number(floors)
})
let floorsBlock = document.getElementById(`floors-${area}-${floors}`);
document.getElementById(`buttonApartment-${area}-${floors}`).remove();
floorsBlock.innerHTML += `
<div class="block-apartments-number" id="block-apartments-${area}-${new_id}">
<input type="text" value="${numApartments}" id="apartament-${area}-${new_id}" onchange="Constructor.apartments.editApartment('${area}', '${new_id}')">
<button type="button" onclick="Constructor.apartments.deleteApartment('${area}', '${new_id}')">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>
</button>
</div>
`;
floorsBlock.innerHTML += `<button class="addApartment" id="buttonApartment-${area}-${floors}" title="Додати квартиру" type="button" onclick="Constructor.apartments.addApartment('${area}', '${floors}')"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg></button>`
numApartments++;
let next_apartment_title = document.getElementById('next-apartment-title');
next_apartment_title.value = numApartments;
},
editApartment: (area, apartament) => {
let input = document.getElementById(`apartament-${area}-${apartament}`);
input.setAttribute("value", input.value);
const pos = Constructor.info.apartments[area].map(e => e.editor_id).indexOf(apartament);
info.apartments[area][pos].title = input.value;
},
deleteApartment: (area, apartament) => {
document.getElementById(`block-apartments-${area}-${apartament}`).remove();
const pos = Constructor.info.apartments[area].map(e => e.editor_id).indexOf(apartament);
Constructor.info.apartments[area].splice(pos, 1);
numApartments--;
let next_apartment_title = document.getElementById('next-apartment-title');
next_apartment_title.value = numApartments;
}
},
osm: {
init: () => {
let center = { lat: 49.5629016, lng: 25.6145625 };
let zoom = 19;
let googleHybrid = L.tileLayer('http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', {
maxZoom: 20,
minZoom: 15,
subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
});
let osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
minZoom: 15
});
let mytile = L.tileLayer('https://tm.rozenrod.com/webp/{z}/{x}/{y}.webp', {
maxZoom: 20,
minZoom: 15,
tms: true
});
if (!map) {
houseGroup = new L.FeatureGroup();
splitPolygonsGroup = new L.FeatureGroup();
RectangleGroup = new L.FeatureGroup();
entransePolygonsGroup = new L.FeatureGroup();
entranseNumPolygonsGroup = new L.FeatureGroup();
map = L.map('map', {
renderer: L.canvas(),
center,
zoom,
layers: [
googleHybrid,
osm,
mytile,
houseGroup,
entransePolygonsGroup,
entranseNumPolygonsGroup,
splitPolygonsGroup,
RectangleGroup,
],
zoomControl: false
});
let baseMaps = {
"Google Hybrid": googleHybrid,
"OpenStreetMap": osm,
"Territory Map": mytile
};
let overlayMaps = {
"Будинки": houseGroup,
"Під'їзди": entransePolygonsGroup,
"Номера під'їздів": entranseNumPolygonsGroup,
"Слой редактирования": splitPolygonsGroup,
"Слой линейки": RectangleGroup,
};
L.control.layers(baseMaps, overlayMaps, { position: 'bottomright' }).addTo(map);
map.pm.setLang("ua");
map.pm.addControls({
position: 'bottomright',
drawCircleMarker: false,
drawPolyline: false,
drawPolygon: false,
drawRectangle: false,
drawCircle: false,
drawText: false,
drawMarker: false,
cutPolygon: false,
tooltips: false
});
map.pm.toggleControls()
map.pm.setGlobalOptions({
layerGroup: splitPolygonsGroup
})
}
Constructor.editor.init();
},
getOSM: async (wayId) => {
const overpassUrl = `https://overpass-api.de/api/interpreter?data=[out:json];way(${wayId});(._;>;);out;`;
return await fetch(overpassUrl)
.then(response => response.json())
.then(data => {
const nodes = new Map();
data.elements.forEach(el => {
if (el.type === "node") {
nodes.set(el.id, { lat: el.lat, lng: el.lon });
}
});
const way = data.elements.find(el => el.type === "way");
if (way) {
const coordinates = way.nodes.map(nodeId => nodes.get(nodeId));
console.log("Координаты точек:", coordinates);
return [coordinates];
} else {
console.log("Way не найден!");
}
})
.catch(error => console.error("Ошибка запроса:", error));
},
setMap: async () => {
houseGroup.clearLayers();
if (!Constructor.info.osm_id) {
let osm = () => {
const a = document.getElementById("info-osm-title").value;
const b = a.replace(/\s+/g, "").split(',')
return b;
}
Constructor.info.osm_id = osm();
}
for (let i = 0; i < Constructor.info.osm_id.length; i++) {
const element = await Constructor.osm.getOSM(Constructor.info.osm_id[i]);
let coords = [];
element[0].forEach((feature) => coords.push([feature.lat, feature.lng]));
let centerPoint = turf.centerOfMass(turf.polygon([coords]));
if (Constructor.info.type == "homestead") {
map.setView([centerPoint.geometry.coordinates[0], centerPoint.geometry.coordinates[1]], 17);
L.polygon(element, {
color: colorGroup(Constructor.info.group_id),
radius: 500,
fillOpacity: 0.3,
dashArray: '20, 15',
dashOffset: '20',
}).addTo(houseGroup);
} else if (Constructor.info.type == "house") {
map.setView([centerPoint.geometry.coordinates[0], centerPoint.geometry.coordinates[1]], 18);
Constructor.info.points.push(element);
Constructor.info.points_number.push(element[0][0]);
L.polygon(element, {
color: "#585858",
fillColor: colorGroup(Constructor.info.group_id),
fillOpacity: 0.8,
tm_id: `house_${i}`
}).addTo(houseGroup);
}
}
console.log(Constructor.info);
}
},
api: {
setPack: async () => {
let area_form_button = document.getElementById('area-form-button');
area_form_button.innerText = "Зачекайте...";
Constructor.info.geo = await map.getCenter();
Constructor.info.zoom = await map.getZoom();
console.log(Constructor.info);
const uuid = localStorage.getItem('uuid');
const URL = `${CONFIG.api}constructor`;
await fetch(URL, {
method: 'POST',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
},
body: JSON.stringify(Constructor.info)
})
.then(response => {
if (response.status == 200) {
console.log({ 'setPack': 'ok' });
area_form_button.innerText = "Запис додано";
return response.json()
} else {
console.log('err');
area_form_button.innerText = "Помилка запису";
return
}
})
.then(data => {
console.log(data);
Router.navigate((`/territory/manager/${Constructor.info.type}/${data.id}`).replace(window.location.origin, ''));
setTimeout(() => {
area_form_button.innerText = "Зберегти";
}, 3000);
})
.catch(err => {
console.log(err);
area_form_button.innerText = "Помилка запису";
})
}
},
editor: {
init: () => {
map.on('pm:create', function (event) {
let layer = event.layer;
let newCoords = layer.getLatLngs()[0].map(function (coords) {
return [coords.lng, coords.lat];
});
newCoords.push(newCoords[0]);
let turfNew = turf.polygon([newCoords]);
if (mode == 'entranse') {
console.log(L.PM.Utils.findLayers(houseGroup));
for (let i = 0; i < L.PM.Utils.findLayers(houseGroup).length; i++) {
const polygon = L.PM.Utils.findLayers(houseGroup)[i]._latlngs;
let polygonCoords = polygon[0].map(function (coords) {
return [coords.lng, coords.lat];
});
polygonCoords.push(polygonCoords[0]); // Замикаємо полігон
let turfPolygon = turf.polygon([polygonCoords]);
// Пошук точки перехрестя
let intersections = turf.intersect(turfNew, turfPolygon);
if (intersections) {
let points = [];
let coords = [];
intersections.geometry.coordinates[0].forEach(function (feature) {
coords.push([feature[1], feature[0]])
points.push({ lat: feature[1], lng: feature[0] })
});
let centerPoint = turf.centerOfMass(turf.polygon([coords]));
let points_number = { lat: centerPoint.geometry.coordinates[0], lng: centerPoint.geometry.coordinates[1] }
let newID = makeid(6);
Constructor.info.entrance.push({
editor_id: newID,
house_id: null,
entrance_number: Constructor.info.entrance.length,
title: `Під'їзд ${Constructor.info.entrance.length + 1}`,
points: points,
points_number: points_number,
floors_quantity: null,
apartments_quantity: null,
created_at: null
})
Constructor.info.apartments[newID] = [];
Constructor.apartments.init();
let listEntranse = document.getElementById('list-entranse');
listEntranse.style.display = "";
listEntranse.innerHTML += `
<div class="house" style="align-items: center;" id="Entranse_${newID}">
<input type="number" value="${Constructor.info.entrance.length}" id="Entranse_input_${newID}" onchange="Constructor.editor.editEntranse('${newID}')">
<button type="button" onclick="Constructor.editor.dellEntranse('${newID}')">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>
</button>
</div>
`;
L.polygon(coords, { color: 'red' }).addTo(entransePolygonsGroup);
let myIcon = L.divIcon({ className: 'entranse_number', html: `<div class="markerEntranse">${Constructor.info.entrance.length}</div>` });
L.marker(centerPoint.geometry.coordinates, { icon: myIcon }).addTo(entranseNumPolygonsGroup);
}
}
}
});
},
drawEntranse: () => {
mode = 'entranse';
map.pm.setGlobalOptions({
layerGroup: splitPolygonsGroup
})
map.pm.setPathOptions({
color: '#f2bd53',
fillColor: '#f2bd53',
fillOpacity: 0.5,
radius: 500
});
if (map.pm.globalDragModeEnabled()) {
map.pm.disableDraw();
} else {
map.pm.enableDraw("Polygon", {
snappable: true,
snapDistance: 20,
tooltips: false,
templineStyle: { color: '#f2bd53' },
hintlineStyle: { color: '#f2bd53', dashArray: [5, 5] }
});
}
},
drawRectangle: () => {
mode = 'rectangle';
document.getElementById('ruler_divide').style.display = 'block'
document.getElementById('ruler').style.width = "calc(50% - 5px)"
document.getElementById('ruler_divide').style.width = "calc(50% - 5px)"
document.getElementById('ruler').innerHTML = 'Лінійка'
map.pm.toggleControls()
RectangleGroup.clearLayers();
RectangleGroup.addTo(map);
map.pm.setGlobalOptions({
layerGroup: RectangleGroup
})
map.pm.setPathOptions({
color: '#b645ef',
fillColor: '#b645ef',
fillOpacity: 0.5,
radius: 500
});
if (map.pm.globalDragModeEnabled()) {
map.pm.disableDraw();
} else {
map.pm.enableDraw("Rectangle", {
snappable: true,
snapDistance: 20,
tooltips: false,
templineStyle: { color: '#b645ef' },
hintlineStyle: { color: '#b645ef', dashArray: [5, 5] }
});
}
},
ruler: (n) => {
n = prompt('На сколько поделить линейку ?', 2);
const polygon = L.PM.Utils.findLayers(RectangleGroup)[0]._latlngs;
let newCoords = polygon[0].map(function (coords) {
return [coords.lng, coords.lat];
});
newCoords.push(newCoords[0]);
let turfNew = turf.polygon([newCoords]);
console.log(turfNew);
var line = turf.polygonToLine(turfNew);
console.log(line.geometry.coordinates);
coords = line.geometry.coordinates;
for (let i = 1; i < n; i++) {
let a1 = (((coords[2][1] - coords[1][1]) / n) * i + coords[1][1])
let b1 = (((coords[2][0] - coords[1][0]) / n) * i + coords[1][0])
let a2 = (((coords[3][1] - coords[0][1]) / n) * i + coords[0][1])
let b2 = (((coords[3][0] - coords[0][0]) / n) * i + coords[0][0])
let c1 = (((coords[1][1] - coords[0][1]) / n) * i + coords[0][1])
let d1 = (((coords[1][0] - coords[0][0]) / n) * i + coords[0][0])
let c2 = (((coords[2][1] - coords[3][1]) / n) * i + coords[3][1])
let d2 = (((coords[2][0] - coords[3][0]) / n) * i + coords[3][0])
L.circleMarker([a1, b1], { radius: 2, color: 'red' }).addTo(RectangleGroup);
L.circleMarker([a2, b2], { radius: 2, color: 'red' }).addTo(RectangleGroup);
L.circleMarker([c1, d1], { radius: 2, color: 'red' }).addTo(RectangleGroup);
L.circleMarker([c2, d2], { radius: 2, color: 'red' }).addTo(RectangleGroup);
}
coords.forEach(function (feature) {
L.circleMarker([feature[1], feature[0]], { radius: 2, color: 'red' }).addTo(RectangleGroup);
});
},
dellEntranse: (id) => {
delete Constructor.info.apartments[id];
const pos = Constructor.info.entrance.map(e => e.editor_id).indexOf(id);
console.log(pos);
Constructor.info.entrance.splice(pos, 1);
console.log(id);
document.getElementById(`Entranse_${id}`).remove();
let Entranse = Object.keys(entransePolygonsGroup._layers);
let numsEntranse = Object.keys(entranseNumPolygonsGroup._layers);
console.log(Entranse, Entranse[pos]);
console.log(numsEntranse, numsEntranse[pos]);
entransePolygonsGroup.removeLayer(entransePolygonsGroup._layers[Entranse[pos]]);
entranseNumPolygonsGroup.removeLayer(entranseNumPolygonsGroup._layers[numsEntranse[pos]]);
Constructor.apartments.init();
},
editEntranse: (id) => {
const input = document.getElementById(`Entranse_input_${id}`);
const pos = Constructor.info.entrance.map(e => e.editor_id).indexOf(id);
Constructor.info.entrance[pos].entrance_number = Number(input.value) - 1;
Constructor.info.entrance[pos].title = `Під'їзд ${input.value}`;
let numsEntranse = Object.keys(entranseNumPolygonsGroup._layers);
let newIcon = L.divIcon({ className: 'entranse_number', html: `<div class="markerEntranse">${input.value}</div>` });
entranseNumPolygonsGroup._layers[numsEntranse[pos]].setIcon(newIcon);
input.setAttribute("value", input.value);
Constructor.apartments.init();
}
}
}

View File

@@ -0,0 +1,494 @@
.page-constructor {
width: calc(100% - 40px);
display: flex;
flex-direction: column;
align-items: center;
margin: 20px 20px 0 20px;
}
.page-constructor form>button {
border-radius: 6px;
background: var(--PrimaryColor);
color: var(--PrimaryColorText);
width: 100%;
height: 40px;
font-size: 14px;
font-weight: 400;
margin: 20px 0;
text-transform: uppercase;
}
.page-constructor details {
border-radius: 10px;
width: 100%;
display: flex;
flex-direction: column;
align-items: stretch;
margin-bottom: 20px;
background: var(--ColorThemes1);
color: var(--ColorThemes3);
border: 1px solid var(--ColorThemes2);
box-shadow: var(--shadow-l1);
}
.page-constructor>details[disabled] summary,
.page-constructor>details.disabled summary {
pointer-events: none;
user-select: none;
}
.page-constructor>details summary::-webkit-details-marker,
.page-constructor>details summary::marker {
display: none;
content: "";
}
.page-constructor summary {
width: calc(100% - 40px);
cursor: pointer;
color: var(--ColorThemes3);
border-radius: var(--border-radius);
font-size: 16px;
font-weight: 300;
padding: 20px;
position: relative;
}
.page-constructor summary span {
font-weight: 500;
}
.page-constructor summary input {
font-weight: 500;
position: absolute;
right: 0;
top: 0;
padding: 10px;
margin: 13px;
font-size: 12px;
background: var(--ColorThemes3);
color: var(--ColorThemes0);
border-radius: 6px;
width: 40px;
}
.page-constructor #info-form,
.page-constructor #map-form,
.page-constructor #area-form {
padding: 0 20px;
}
#details-info-type {
display: flex;
align-items: center;
justify-content: center;
}
#details-info-type>.tabs {
display: flex;
position: relative;
background-color: var(--ColorThemes0);
padding: 4px;
border-radius: 6px;
width: calc(100% - 8px);
z-index: 2;
}
#details-info-type>.tabs>input[type="radio"] {
display: none;
}
#details-info-type>.tabs>.tab {
display: flex;
align-items: center;
justify-content: center;
height: 40px;
width: calc(100% / 3);
cursor: pointer;
padding: 0 15px;
transition: 0.15s ease-in;
color: var(--ColorThemes3);
fill: var(--ColorThemes3);
flex-direction: row;
z-index: 2;
}
#details-info-type>.tabs>.tab>svg {
width: 20px;
height: 20px;
}
#details-info-type>.tabs>.tab>span {
margin-left: 6px;
font-size: 12px;
font-weight: 400;
}
#details-info-type>.tabs>input[type="radio"]:checked+label {
color: var(--PrimaryColorText);
fill: var(--PrimaryColorText);
}
#details-info-type>.tabs>.glider {
position: absolute;
display: flex;
height: 40px;
width: calc((100% - 8px) / 3);
background-color: var(--PrimaryColor);
z-index: 1;
border-radius: 4px;
transition: 0.25s ease-out;
}
@media (min-width: 601px) {
#details-info-type>.tabs>input[id="info-type-house"]:checked~.glider {
transform: translateX(0);
}
#details-info-type>.tabs>input[id="info-type-homestead"]:checked~.glider {
transform: translateX(100%);
}
#details-info-type>.tabs>input[id="info-type-points"]:checked~.glider {
transform: translateX(200%);
}
}
@media (max-width: 600px) {
#details-info-type>.tabs {
flex-direction: column;
}
#details-info-type>.tabs>.tab {
width: calc(100% - 8px);
padding: 0 4px;
}
#details-info-type>.tabs>.glider {
width: calc(100% - 8px);
}
#details-info-type>.tabs>input[id="info-type-house"]:checked~.glider {
transform: translateY(0);
}
#details-info-type>.tabs>input[id="info-type-homestead"]:checked~.glider {
transform: translateY(100%);
}
#details-info-type>.tabs>input[id="info-type-points"]:checked~.glider {
transform: translateY(200%);
}
}
.page-constructor .details-info-input {
width: 100%;
display: flex;
margin: 20px 0;
align-items: flex-start;
flex-direction: column;
}
.page-constructor .details-info-input label {
display: flex;
justify-content: center;
flex-direction: column;
font-size: 12px;
font-weight: 500;
margin-bottom: 5px;
}
.page-constructor .details-info-input input {
width: calc(100% - 10px);
min-width: 140px;
padding: 0 5px;
border-radius: 6px;
height: 30px;
background: var(--ColorThemes0);
color: var(--ColorThemes3);
}
.page-constructor #details-info-osm div {
display: flex;
align-items: center;
width: 100%;
}
.page-constructor #details-info-osm input {
width: calc(100% - 10px);
min-width: 140px;
padding: 0 5px;
border-radius: 6px;
height: 30px;
}
.page-constructor .details-info-input a {
height: 26px;
width: 26px;
margin-left: 10px;
}
.page-constructor .details-info-input a>svg {
height: 26px;
width: 26px;
fill: var(--ColorThemes3)
}
.page-constructor #list-area {
margin-top: 15px;
display: flex;
overflow: auto;
}
.page-constructor #list-area h3 {
text-align: center;
font-size: 16px;
font-weight: 400;
margin: 10px;
padding: 7px;
color: var(--ColorThemes0);
background: var(--ColorThemes3);
border-radius: 4px;
}
.block-area {
min-height: 200px;
border: 1px solid var(--ColorThemes3);
border-style: dashed;
border-radius: 6px;
margin: 0 10px 10px 0;
}
.addFloors,
.addApartment {
display: flex;
position: relative;
width: 34px;
height: 34px;
background: var(--PrimaryColor);
color: var(--PrimaryColorText);
margin: 25px;
border-radius: 50%;
align-items: center;
justify-content: center;
font-size: 30px;
cursor: pointer;
}
.addFloors>svg,
.addApartment>svg {
width: 20px;
height: 20px;
fill: var(--PrimaryColorText);
transform: rotate(45deg);
}
.block-apartments-floors {
position: relative;
display: flex;
width: calc(100% - 22px);
border: 1px solid var(--ColorThemes3);
margin: 10px;
border-radius: 4px;
}
.block-apartments-floors h2 {
position: absolute;
width: 65px;
right: -1px;
top: -1px;
margin: 0;
background: var(--ColorThemes3);
color: var(--ColorThemes2);
border-radius: 0 4px 0 4px;
font-size: 12px;
padding: 2px 4px;
text-align: center;
}
.block-apartments-number {
display: flex;
position: relative;
width: 60px;
height: 60px;
background: var(--ColorThemes1);
border: 2px solid var(--PrimaryColor);
margin: 10px;
border-radius: 4px;
align-items: center;
justify-content: center;
}
.block-apartments-number input {
width: 50px;
height: 50px;
font-size: 16px;
font-weight: 400;
text-align: center;
color: var(--ColorThemes3);
background: 0;
}
.block-apartments-number button {
position: absolute;
top: 0;
right: 0;
width: 20px;
height: 20px;
border-radius: 0 4px 0 4px;
background: var(--PrimaryColor);
font-size: 16px;
margin: -2px;
border: 0;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.block-apartments-number button>svg {
width: 16px;
height: 16px;
fill: var(--PrimaryColorText);
}
.block-map {
width: 100%;
height: 500px;
border-radius: 6px;
overflow: hidden;
}
#map {
width: 100%;
height: 100%;
}
.entranse_number {
left: -10px !important;
top: -10px !important;
}
.markerEntranse {
background: hsl(0deg 0% 52.12% / 90%);
font-size: 24px;
border: 2px solid #676767;
border-radius: 2px;
display: flex !important;
justify-content: center;
align-items: center;
color: #fff;
min-width: 30px;
min-height: 30px;
height: 30px;
width: 30px;
}
.editor-buttons {
margin-top: 15px;
}
.editor-buttons>button {
width: 100%;
min-height: 30px;
margin: 5px 0;
border: 0;
color: var(--PrimaryColorText);
display: flex;
align-items: center;
justify-content: center;
background: var(--PrimaryColor);
text-transform: uppercase;
cursor: pointer;
border-radius: 6px;
font-weight: 400;
font-size: 12px;
}
.editor-buttons>div {
display: flex;
width: 100%;
margin: 10px 0;
height: 30px;
justify-content: space-between;
}
.editor-buttons>div>button {
background: var(--ColorThemes3);
color: var(--ColorThemes1);
width: 100%;
margin: 0;
border-radius: 6px;
text-transform: uppercase;
font-weight: 400;
font-size: 12px;
}
.page-constructor #list-entranse,
.page-constructor #list-homestead {
width: 100%;
min-height: 86px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
overflow-x: initial;
overflow-y: auto;
border: 1px solid var(--ColorThemes3);
background: 0;
border-radius: 6px;
border-style: dashed;
margin: 10px 0;
}
.page-constructor #list-entranse>.house,
.page-constructor #list-homestead>.house {
display: flex;
position: relative;
width: 60px;
height: 60px;
background: var(--ColorThemes1);
border: 2px solid var(--PrimaryColor);
margin: 10px;
border-radius: 4px;
align-items: center;
justify-content: center;
}
.page-constructor #list-entranse>.house>input,
.page-constructor #list-homestead>.house>input {
width: 50px;
height: 50px;
font-size: 16px;
font-weight: 400;
text-align: center;
color: var(--ColorThemes3);
background: 0;
}
.page-constructor #list-entranse>.house>button,
.page-constructor #list-homestead>.house>button {
position: absolute;
top: 0;
right: 0;
width: 20px;
height: 20px;
border-radius: 0 4px 0 4px;
background: var(--PrimaryColor);
font-size: 16px;
margin: -2px;
border: 0;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.page-constructor #list-entranse>.house>button>svg,
.page-constructor #list-homestead>.house>button>svg {
width: 16px;
height: 16px;
fill: var(--PrimaryColorText);
}

View File

@@ -0,0 +1,139 @@
<div class="page-editor">
<details id="details-info" open>
<summary>
<span>Крок 1.</span> Інформація про будинок, територію, точки на карті
</summary>
<form id="info-form">
<div id="details-info-address" class="details-info-input">
<label for="info-address-title">Назва вулиці</label>
<input
type="text"
id="info-address-title"
name="address"
required
value=""
/>
</div>
<div id="details-info-number" class="details-info-input">
<label for="info-number-title">Номер будинку</label>
<input
type="text"
id="info-number-title"
name="number"
required
value=""
/>
</div>
<div id="details-info-settlement" class="details-info-input">
<label for="info-settlement-title">Місто</label>
<input
type="text"
id="info-settlement-title"
name="settlement"
required
value=""
/>
</div>
<div id="details-info-group" class="details-info-input">
<label for="info-group-title">Теократична група</label>
<input
type="number"
id="info-group-title"
name="group"
required
value=""
/>
</div>
<div id="details-info-osm" class="details-info-input">
<label for="info-settlement-title">OSM iD</label>
<div>
<input
type="text"
id="info-osm-title"
name="osm"
placeholder="123, 345, 678"
required
value=""
/>
<a href="https://www.openstreetmap.org/#map=19/49.561725/25.604458" target="_blank" title="Де знайти OSM iD ?"
><svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 48 48"
width="100px"
height="100px"
>
<path
d="M 24 4 C 12.972066 4 4 12.972074 4 24 C 4 35.027926 12.972066 44 24 44 C 35.027934 44 44 35.027926 44 24 C 44 12.972074 35.027934 4 24 4 z M 24 7 C 33.406615 7 41 14.593391 41 24 C 41 33.406609 33.406615 41 24 41 C 14.593385 41 7 33.406609 7 24 C 7 14.593391 14.593385 7 24 7 z M 24 14 A 2 2 0 0 0 24 18 A 2 2 0 0 0 24 14 z M 23.976562 20.978516 A 1.50015 1.50015 0 0 0 22.5 22.5 L 22.5 33.5 A 1.50015 1.50015 0 1 0 25.5 33.5 L 25.5 22.5 A 1.50015 1.50015 0 0 0 23.976562 20.978516 z"
/></svg
></a>
</div>
</div>
</form>
</details>
<details id="details-map" open>
<summary id="details-map-title">
<span>Крок 2.</span> Перегляд
</summary>
<form id="map-form">
<!-- <div class="editor-buttons" id="details-map-buttons-entranse">
<button type="button" onclick="Editor.editor.drawEntranse()">
Створити новий під'їзд
</button>
<div>
<button type="button" id="ruler" onclick="Editor.editor.drawRectangle()">
Лінійка
</button>
<button
type="button"
id="ruler_divide"
onclick="Editor.editor.ruler()"
style="display: none"
>
Поділити
</button>
</div>
</div> -->
<div
class="editor-buttons"
id="details-map-buttons-homestead"
style="display: none"
>
<!-- <div>
<button type="button" id="ruler" onclick="Editor.editor.drawRectangle()">
Лінійка
</button>
<button
type="button"
id="ruler_divide"
onclick="Editor.editor.ruler()"
style="display: none"
>
Поділити
</button>
</div> -->
</div>
<div id="list-entranse" style="display: none"></div>
<div id="list-homestead" style="display: none"></div>
<div class="block-map">
<div id="map"></div>
</div>
<button id="map-form-button" type="submit" style="display: none;">Далі</button>
</form>
</details>
<details id="details-area" open style="display: none;">
<summary><span>Крок 3.</span> Конструктор квартир <input type="number" value="1" id="next-apartment-title" onchange="Editor.apartments.editNum(this)" title="Авто-номер наступної квартири"></summary>
<form id="area-form">
<div id="list-area"></div>
</form>
</details>
</div>

View File

@@ -0,0 +1,449 @@
const Editor = {
init: async (type, id) => {
let html = await fetch('/lib/pages/editor/index.html').then((response) => response.text());
app.innerHTML = html;
map = "";
houseGroup = "";
entransePolygonsGroup = "";
entranseNumPolygonsGroup = "";
splitPolygonsGroup = "";
RectangleGroup = "";
numApartments = 1;
Editor.info.setHTML(type, id);
// document.getElementById("area-form").addEventListener("submit", async function (event) {
// event.preventDefault();
// await Editor.api.setPack();
// })
},
loadAPI: async function (URL) {
let uuid = localStorage.getItem("uuid");
return await fetch(URL, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
}).then((response) => response.json());
},
info: {
list: {
type: null,
group_id: null,
title: null,
number: null,
points: [],
points_number: [],
point_icons: [],
geo: [],
osm_id: [],
settlement: [],
description: null,
entrance: [],
apartments: {}
},
setHTML: async (type, id) => {
let detailsInfo_address_title = document.getElementById('info-address-title');
let detailsInfo_number_title = document.getElementById('info-number-title');
let detailsInfo_settlement_title = document.getElementById('info-settlement-title');
let detailsInfo_group_title = document.getElementById('info-group-title');
let detailsInfo_osm_title = document.getElementById('info-osm-title');
Editor.info.list = await Editor.loadAPI(`${CONFIG.api}${type}/${id}`);
Editor.info.list.type = type;
Editor.info.list.entrance = [];
Editor.info.list.apartments = {};
console.log(Editor.info.list);
detailsInfo_address_title.value = Editor.info.list.title;
detailsInfo_number_title.value = Editor.info.list.number;
detailsInfo_settlement_title.value = Editor.info.list.settlement;
detailsInfo_group_title.value = Editor.info.list.group_id;
detailsInfo_osm_title.value = Editor.info.list.osm_id.join(", ");
Editor.osm.init();
Editor.info.setMap();
if (type == "house") {
Editor.entrances.setHTML(id);
document.getElementById('details-area').style.display = "";
}
},
setMap: async () => {
houseGroup.clearLayers();
for (let i = 0; i < Editor.info.list.points.length; i++) {
const element = Editor.info.list.points[i];
if (Editor.info.list.type == "homestead") {
map.setView([Editor.info.list.geo.lat, Editor.info.list.geo.lng], 17);
L.polygon(element, {
color: colorGroup(Editor.info.list.group_id),
radius: 500,
fillOpacity: 0.3,
dashArray: '20, 15',
dashOffset: '20',
}).addTo(houseGroup);
} else if (Editor.info.list.type == "house") {
map.setView([Editor.info.list.geo.lat, Editor.info.list.geo.lng], 18);
L.polygon(element, {
color: "#585858",
fillColor: colorGroup(Editor.info.list.group_id),
fillOpacity: 0.8,
tm_id: `house_${i}`
}).addTo(houseGroup);
}
}
}
},
entrances: {
list: [],
setHTML: async (id) => {
Editor.entrances.list = await Editor.loadAPI(`${CONFIG.api}house/${id}/entrances`);
console.log(Editor.entrances.list);
Editor.entrances.setMap()
},
setMap: async () => {
entransePolygonsGroup.clearLayers();
entranseNumPolygonsGroup.clearLayers();
for (let i = 0; i < Editor.entrances.list.length; i++) {
const element = Editor.entrances.list[i];
console.log(element);
let listEntranse = document.getElementById('list-entranse');
listEntranse.style.display = "";
listEntranse.innerHTML += `
<div class="house" style="align-items: center;" id="Entranse_${element.id}">
<p>${element.entrance_number + 1}</p>
</div>
`;
let listArea = document.getElementById('list-area');
listArea.innerHTML += `
<div class="block-area" id="block-area-${element.id}">
<h3>${element.title}</h3>
<button class="addFloors" title="Додати поверх" type="button" onclick="Editor.apartments.addFloors('${element.id}')"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg></button>
<div id="area-${element.id}"></div>
</div>
`;
Editor.apartments.setHTML(element.id);
L.polygon(element.points, { color: 'red' }).addTo(entransePolygonsGroup);
let myIcon = L.divIcon({ className: 'entranse_number', html: `<div class="markerEntranse">${element.entrance_number + 1}</div>` });
L.marker(element.points_number, { icon: myIcon }).addTo(entranseNumPolygonsGroup);
}
}
},
apartments: {
list: [],
setHTML: async (id) => {
Editor.apartments.list[`${id}`] = await Editor.loadAPI(`${CONFIG.api}apartments/${id}`);
const uniqueFloors = [...new Set(Editor.apartments.list[`${id}`].map(item => item.floors_number))];
for (let i = 0; i < uniqueFloors.length; i++) {
let num = uniqueFloors[i];
let area = document.getElementById(`area-${id}`);
let div = document.createElement('div');
div.className = "block-apartments-floors";
div.id = `floors-${id}-${num}`
div.innerHTML = `
<h2>Поверх ${num}</h2>
<button class="addApartment" id="buttonApartment-${id}-${num}" title="Додати квартиру" type="button" onclick="Editor.apartments.addApartment('${id}', '${num}')"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg></button>
`;
area.prepend(div);
}
Editor.apartments.list[`${id}`].sort((a, b) => b.title - a.title);
for (let i = 0; i < Editor.apartments.list[`${id}`].length; i++) {
const apartment = Editor.apartments.list[`${id}`][i];
let num = apartment.floors_number;
let floorsBlock = document.getElementById(`floors-${id}-${num}`);
let div = document.createElement('div');
div.className = "block-apartments-number";
div.id = `block-apartments-${id}-${apartment.id}`
div.innerHTML = `
<input type="text" value="${apartment.title}" id="apartament-${id}-${apartment.id}" onchange="Editor.apartments.editApartment('${id}','${apartment.id}')">
<button type="button" onclick="Editor.apartments.deleteApartment('${id}','${apartment.id}')">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>
</button>
`;
floorsBlock.prepend(div);
numApartments++;
let next_apartment_title = document.getElementById('next-apartment-title');
next_apartment_title.value = numApartments;
}
},
editNum: (element) => {
numApartments = Number(element.value);
},
addFloors: async (area) => {
let areaBlock = document.getElementById(`area-${area}`);
let uniqueFloors = [...new Set(Editor.apartments.list[area].map(obj => obj.floors_number))];
let new_floors = uniqueFloors.length + 1;
const uuid = localStorage.getItem('uuid');
const URL = `${CONFIG.api}/apartments/${area}`;
await fetch(URL, {
method: 'POST',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
},
body: JSON.stringify({
apartment_number: Editor.apartments.list[area].length,
title: numApartments.toString(),
floors_number: Number(new_floors)
})
})
.then(response => response.json())
.then(data => {
console.log(data);
let div = document.createElement('div');
div.className = "block-apartments-floors";
div.id = `floors-${area}-${new_floors}`
div.innerHTML = `
<h2>Поверх ${new_floors}</h2>
<div class="block-apartments-number" id="block-apartments-${area}-${data.id}">
<input type="text" value="${numApartments}" id="apartament-${area}-${data.id}" onchange="Editor.apartments.editApartment('${area}', '${data.id}')">
<button type="button" onclick="Editor.apartments.deleteApartment('${area}', '${data.id}')">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>
</button>
</div>
<button class="addApartment" id="buttonApartment-${area}-${new_floors}" title="Додати квартиру" type="button" onclick="Editor.apartments.addApartment('${area}', '${new_floors}')"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg></button>
`
areaBlock.prepend(div);
console.log(Editor.apartments.list[area]);
Editor.apartments.list[area].push({
id: data.id,
entrance_id: Number(area),
apartment_number: Editor.apartments.list[area].length,
title: numApartments.toString(),
floors_number: Number(new_floors)
});
numApartments++;
let next_apartment_title = document.getElementById('next-apartment-title');
next_apartment_title.value = numApartments;
})
.catch(err => {
console.log(err);
})
},
addApartment: async (area, floors) => {
const uuid = localStorage.getItem('uuid');
const URL = `${CONFIG.api}/apartments/${area}`;
await fetch(URL, {
method: 'POST',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
},
body: JSON.stringify({
apartment_number: Editor.apartments.list[area].length,
title: numApartments.toString(),
floors_number: Number(floors)
})
})
.then(response => response.json())
.then(data => {
console.log(data);
Editor.apartments.list[area].push({
id: data.id,
entrance_id: Number(area),
apartment_number: Editor.apartments.list[area].length,
title: numApartments.toString(),
floors_number: Number(floors)
});
let floorsBlock = document.getElementById(`floors-${area}-${floors}`);
document.getElementById(`buttonApartment-${area}-${floors}`).remove();
floorsBlock.innerHTML += `
<div class="block-apartments-number" id="block-apartments-${area}-${data.id}">
<input type="text" value="${numApartments}" id="apartament-${area}-${data.id}" onchange="Editor.apartments.editApartment('${area}', '${data.id}')">
<button type="button" onclick="Editor.apartments.deleteApartment('${area}', '${data.id}')">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>
</button>
</div>
`;
floorsBlock.innerHTML += `<button class="addApartment" id="buttonApartment-${area}-${floors}" title="Додати квартиру" type="button" onclick="Editor.apartments.addApartment('${area}', '${floors}')"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg></button>`
numApartments++;
let next_apartment_title = document.getElementById('next-apartment-title');
next_apartment_title.value = numApartments;
})
.catch(err => {
console.log(err);
})
},
editApartment: async (area, apartament) => {
let input = document.getElementById(`apartament-${area}-${apartament}`);
input.setAttribute("value", input.value);
const pos = Editor.apartments.list[area].map(e => e.id).indexOf(Number(apartament));
Editor.apartments.list[area][pos].title = input.value;
const uuid = localStorage.getItem('uuid');
const URL = `${CONFIG.api}/apartments/${area}`;
await fetch(URL, {
method: 'PUT',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
},
body: JSON.stringify({
title: Editor.apartments.list[area][pos].title,
status: Editor.apartments.list[area][pos].status,
description: Editor.apartments.list[area][pos].description,
id: Editor.apartments.list[area][pos].id
})
})
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(err => {
console.log(err);
})
},
deleteApartment: async (area, apartament) => {
const pos = Editor.apartments.list[area].map(e => e.id).indexOf(Number(apartament));
const uuid = localStorage.getItem('uuid');
const URL = `${CONFIG.api}/apartments/${area}`;
await fetch(URL, {
method: 'DELETE',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
},
body: JSON.stringify({
id: Editor.apartments.list[area][pos].id
})
})
.then(response => response.json())
.then(data => {
console.log(data);
document.getElementById(`block-apartments-${area}-${apartament}`).remove();
Editor.apartments.list[area].splice(pos, 1);
numApartments--;
let next_apartment_title = document.getElementById('next-apartment-title');
next_apartment_title.value = numApartments;
})
.catch(err => {
console.log(err);
})
}
},
osm: {
init: () => {
let center = { lat: 49.5629016, lng: 25.6145625 };
let zoom = 19;
let googleHybrid = L.tileLayer('http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', {
maxZoom: 20,
minZoom: 15,
subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
});
let osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
minZoom: 15
});
let mytile = L.tileLayer('https://tm.rozenrod.com/webp/{z}/{x}/{y}.webp', {
maxZoom: 20,
minZoom: 15,
tms: true
});
if (!map) {
houseGroup = new L.FeatureGroup();
splitPolygonsGroup = new L.FeatureGroup();
RectangleGroup = new L.FeatureGroup();
entransePolygonsGroup = new L.FeatureGroup();
entranseNumPolygonsGroup = new L.FeatureGroup();
map = L.map('map', {
renderer: L.canvas(),
center,
zoom,
layers: [
googleHybrid,
osm,
mytile,
houseGroup,
entransePolygonsGroup,
entranseNumPolygonsGroup,
splitPolygonsGroup,
RectangleGroup,
],
zoomControl: false
});
let baseMaps = {
"Google Hybrid": googleHybrid,
"OpenStreetMap": osm,
"Territory Map": mytile
};
let overlayMaps = {
"Будинки": houseGroup,
"Під'їзди": entransePolygonsGroup,
"Номера під'їздів": entranseNumPolygonsGroup,
"Слой редактирования": splitPolygonsGroup,
"Слой линейки": RectangleGroup,
};
L.control.layers(baseMaps, overlayMaps, { position: 'bottomright' }).addTo(map);
map.pm.setLang("ua");
map.pm.addControls({
position: 'bottomright',
drawCircleMarker: false,
drawPolyline: false,
drawPolygon: false,
drawRectangle: false,
drawCircle: false,
drawText: false,
drawMarker: false,
cutPolygon: false,
tooltips: false
});
map.pm.toggleControls()
map.pm.setGlobalOptions({
layerGroup: splitPolygonsGroup
})
}
}
}
}

View File

@@ -0,0 +1,500 @@
.page-editor {
width: calc(100% - 40px);
display: flex;
flex-direction: column;
align-items: center;
margin: 20px 20px 0 20px;
}
.page-editor form>button {
border-radius: 6px;
background: var(--PrimaryColor);
color: var(--PrimaryColorText);
width: 100%;
height: 40px;
font-size: 14px;
font-weight: 400;
margin: 20px 0;
text-transform: uppercase;
}
.page-editor details {
border-radius: 10px;
width: 100%;
display: flex;
flex-direction: column;
align-items: stretch;
margin-bottom: 20px;
background: var(--ColorThemes1);
color: var(--ColorThemes3);
border: 1px solid var(--ColorThemes2);
box-shadow: var(--shadow-l1);
}
.page-editor>details[disabled] summary,
.page-editor>details.disabled summary {
pointer-events: none;
user-select: none;
}
.page-editor>details summary::-webkit-details-marker,
.page-editor>details summary::marker {
display: none;
content: "";
}
.page-editor summary {
width: calc(100% - 40px);
cursor: pointer;
color: var(--ColorThemes3);
border-radius: var(--border-radius);
font-size: 16px;
font-weight: 300;
padding: 20px;
position: relative;
}
.page-editor summary span {
font-weight: 500;
}
.page-editor summary input {
font-weight: 500;
position: absolute;
right: 0;
top: 0;
padding: 10px;
margin: 13px;
font-size: 12px;
background: var(--ColorThemes3);
color: var(--ColorThemes0);
border-radius: 6px;
width: 40px;
}
.page-editor #info-form,
.page-editor #map-form,
.page-editor #area-form {
padding: 0 20px;
}
#details-info-type {
display: flex;
align-items: center;
justify-content: center;
}
#details-info-type>.tabs {
display: flex;
position: relative;
background-color: var(--ColorThemes0);
padding: 4px;
border-radius: 6px;
width: calc(100% - 8px);
z-index: 2;
}
#details-info-type>.tabs>input[type="radio"] {
display: none;
}
#details-info-type>.tabs>.tab {
display: flex;
align-items: center;
justify-content: center;
height: 40px;
width: calc(100% / 3);
cursor: pointer;
padding: 0 15px;
transition: 0.15s ease-in;
color: var(--ColorThemes3);
fill: var(--ColorThemes3);
flex-direction: row;
z-index: 2;
}
#details-info-type>.tabs>.tab>svg {
width: 20px;
height: 20px;
}
#details-info-type>.tabs>.tab>span {
margin-left: 6px;
font-size: 12px;
font-weight: 400;
}
#details-info-type>.tabs>input[type="radio"]:checked+label {
color: var(--PrimaryColorText);
fill: var(--PrimaryColorText);
}
#details-info-type>.tabs>.glider {
position: absolute;
display: flex;
height: 40px;
width: calc((100% - 8px) / 3);
background-color: var(--PrimaryColor);
z-index: 1;
border-radius: 4px;
transition: 0.25s ease-out;
}
@media (min-width: 601px) {
#details-info-type>.tabs>input[id="info-type-house"]:checked~.glider {
transform: translateX(0);
}
#details-info-type>.tabs>input[id="info-type-homestead"]:checked~.glider {
transform: translateX(100%);
}
#details-info-type>.tabs>input[id="info-type-points"]:checked~.glider {
transform: translateX(200%);
}
}
@media (max-width: 600px) {
#details-info-type>.tabs {
flex-direction: column;
}
#details-info-type>.tabs>.tab {
width: calc(100% - 8px);
padding: 0 4px;
}
#details-info-type>.tabs>.glider {
width: calc(100% - 8px);
}
#details-info-type>.tabs>input[id="info-type-house"]:checked~.glider {
transform: translateY(0);
}
#details-info-type>.tabs>input[id="info-type-homestead"]:checked~.glider {
transform: translateY(100%);
}
#details-info-type>.tabs>input[id="info-type-points"]:checked~.glider {
transform: translateY(200%);
}
}
.page-editor .details-info-input {
width: 100%;
display: flex;
margin: 20px 0;
align-items: flex-start;
flex-direction: column;
}
.page-editor .details-info-input label {
display: flex;
justify-content: center;
flex-direction: column;
font-size: 12px;
font-weight: 500;
margin-bottom: 5px;
}
.page-editor .details-info-input input {
width: calc(100% - 10px);
min-width: 140px;
padding: 0 5px;
border-radius: 6px;
height: 30px;
background: var(--ColorThemes0);
color: var(--ColorThemes3);
}
.page-editor #details-info-osm div {
display: flex;
align-items: center;
width: 100%;
}
.page-editor #details-info-osm input {
width: calc(100% - 10px);
min-width: 140px;
padding: 0 5px;
border-radius: 6px;
height: 30px;
}
.page-editor .details-info-input a {
height: 26px;
width: 26px;
margin-left: 10px;
}
.page-editor .details-info-input a>svg {
height: 26px;
width: 26px;
fill: var(--ColorThemes3)
}
.page-editor #list-area {
display: flex;
overflow: auto;
margin: 15px 0 20px 0;
}
.page-editor #list-area h3 {
text-align: center;
font-size: 16px;
font-weight: 400;
margin: 10px;
padding: 7px;
color: var(--ColorThemes0);
background: var(--ColorThemes3);
border-radius: 4px;
}
.block-area {
min-height: 200px;
border: 1px solid var(--ColorThemes3);
border-style: dashed;
border-radius: 6px;
margin: 0 10px 10px 0;
}
.addFloors,
.addApartment {
display: flex;
position: relative;
width: 34px;
height: 34px;
background: var(--PrimaryColor);
color: var(--PrimaryColorText);
margin: 25px;
border-radius: 50%;
align-items: center;
justify-content: center;
font-size: 30px;
cursor: pointer;
}
.addFloors>svg,
.addApartment>svg {
width: 20px;
height: 20px;
fill: var(--PrimaryColorText);
transform: rotate(45deg);
}
.block-apartments-floors {
position: relative;
display: flex;
width: calc(100% - 22px);
border: 1px solid var(--ColorThemes3);
margin: 10px;
border-radius: 4px;
}
.block-apartments-floors h2 {
position: absolute;
width: 65px;
right: -1px;
top: -1px;
margin: 0;
background: var(--ColorThemes3);
color: var(--ColorThemes2);
border-radius: 0 4px 0 4px;
font-size: 12px;
padding: 2px 4px;
text-align: center;
}
.block-apartments-number {
display: flex;
position: relative;
width: 60px;
height: 60px;
background: var(--ColorThemes1);
border: 2px solid var(--PrimaryColor);
margin: 10px;
border-radius: 4px;
align-items: center;
justify-content: center;
}
.block-apartments-number input {
width: 50px;
height: 50px;
font-size: 16px;
font-weight: 400;
text-align: center;
color: var(--ColorThemes3);
background: 0;
}
.block-apartments-number button {
position: absolute;
top: 0;
right: 0;
width: 20px;
height: 20px;
border-radius: 0 4px 0 4px;
background: var(--PrimaryColor);
font-size: 16px;
margin: -2px;
border: 0;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.block-apartments-number button>svg {
width: 16px;
height: 16px;
fill: var(--PrimaryColorText);
}
.block-map {
width: 100%;
height: 500px;
border-radius: 6px;
overflow: hidden;
margin-bottom: 20px;
}
#map {
width: 100%;
height: 100%;
}
.entranse_number {
left: -10px !important;
top: -10px !important;
}
.markerEntranse {
background: hsl(0deg 0% 52.12% / 90%);
font-size: 24px;
border: 2px solid #676767;
border-radius: 2px;
display: flex !important;
justify-content: center;
align-items: center;
color: #fff;
min-width: 30px;
min-height: 30px;
height: 30px;
width: 30px;
}
.editor-buttons {
margin-top: 15px;
}
.editor-buttons>button {
width: 100%;
min-height: 30px;
margin: 5px 0;
border: 0;
color: var(--PrimaryColorText);
display: flex;
align-items: center;
justify-content: center;
background: var(--PrimaryColor);
text-transform: uppercase;
cursor: pointer;
border-radius: 6px;
font-weight: 400;
font-size: 12px;
}
.editor-buttons>div {
display: flex;
width: 100%;
margin: 10px 0;
height: 30px;
justify-content: space-between;
}
.editor-buttons>div>button {
background: var(--ColorThemes3);
color: var(--ColorThemes1);
width: 100%;
margin: 0;
border-radius: 6px;
text-transform: uppercase;
font-weight: 400;
font-size: 12px;
}
.page-editor #list-entranse,
.page-editor #list-homestead {
width: 100%;
min-height: 86px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
overflow-x: initial;
overflow-y: auto;
border: 1px solid var(--ColorThemes3);
background: 0;
border-radius: 6px;
border-style: dashed;
margin: 10px 0;
}
.page-editor #list-entranse>.house,
.page-editor #list-homestead>.house {
display: flex;
position: relative;
width: 60px;
height: 60px;
background: var(--ColorThemes1);
border: 2px solid var(--PrimaryColor);
margin: 10px;
border-radius: 4px;
align-items: center;
justify-content: center;
}
.page-editor #list-entranse>.house>input,
.page-editor #list-homestead>.house>input,
.page-editor #list-entranse>.house>p,
.page-editor #list-homestead>.house>p {
width: 50px;
height: 50px;
font-size: 16px;
font-weight: 400;
text-align: center;
color: var(--ColorThemes3);
background: 0;
display: flex;
align-items: center;
justify-content: center;
}
.page-editor #list-entranse>.house>button,
.page-editor #list-homestead>.house>button {
position: absolute;
top: 0;
right: 0;
width: 20px;
height: 20px;
border-radius: 0 4px 0 4px;
background: var(--PrimaryColor);
font-size: 16px;
margin: -2px;
border: 0;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.page-editor #list-entranse>.house>button>svg,
.page-editor #list-homestead>.house>button>svg {
width: 16px;
height: 16px;
fill: var(--PrimaryColorText);
}

View File

@@ -0,0 +1,9 @@
<div class="page-home">
<details id="details-personal-territory" open>
<summary>
<span>Території для опрацювання</span>
</summary>
<div id="home-personal-territory-list"></div>
</details>
</div>

View File

@@ -0,0 +1,95 @@
const Home = {
init: async () => {
let html = await fetch('/lib/pages/home/index.html').then((response) => response.text());
app.innerHTML = html;
Home.house.setHTML();
Home.homestead.setHTML();
},
house: {
loadAPI: async function () {
let uuid = localStorage.getItem("uuid");
const URL = `${CONFIG.api}houses/list?mode=sheep`;
return await fetch(URL, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
}).then((response) => response.json());
},
setHTML: async function () {
let list = await Home.house.loadAPI();
list.sort((a, b) => b.id - a.id);
console.log(list);
let block_house = document.getElementById('home-personal-territory-list')
for (let i = 0; i < list.length; i++) {
const element = list[i];
block_house.innerHTML += `
<div class="card">
<i style="background-image: url(https://sheep-service.com/cards/house/T${element.id}.webp);"></i>
<div class="contents">
<div class="group" style="background: ${colorGroup(element.group_id)}">
<span>Група №${element.group_id}</span>
</div>
<div class="info">
<div>
<p>${element.title} ${element.number}</p>
</div>
</div>
</div>
<a href="/territory/card/house/${element.id}" data-route></a>
</div>
`;
}
}
},
homestead: {
loadAPI: async function () {
let uuid = localStorage.getItem("uuid");
const URL = `${CONFIG.api}homestead/list?mode=sheep`;
return await fetch(URL, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
}).then((response) => response.json());
},
setHTML: async function () {
let list = await Home.homestead.loadAPI();
list.sort((a, b) => b.id - a.id);
console.log(list);
let block_homestead = document.getElementById('home-personal-territory-list')
for (let i = 0; i < list.length; i++) {
const element = list[i];
block_homestead.innerHTML += `
<div class="card">
<i style="background-image: url(https://sheep-service.com/cards/homestead/H${element.id}.webp);"></i>
<div class="contents">
<div class="group" style="background: ${colorGroup(element.group_id)}">
<span>Група №${element.group_id}</span>
</div>
<div class="info">
<div>
<p>${element.title} ${element.number}</p>
</div>
</div>
</div>
<a href="/territory/card/homestead/${element.id}" data-route></a>
</div>
`;
}
}
}
}

View File

@@ -0,0 +1,191 @@
.page-home {
width: calc(100% - 40px);
display: flex;
flex-direction: column;
margin: 20px 20px 0 20px;
}
.page-home details {
border-radius: 15px;
width: 100%;
display: flex;
flex-direction: column;
align-items: stretch;
margin-bottom: 20px;
background: var(--ColorThemes1);
color: var(--ColorThemes3);
border: 1px solid var(--ColorThemes2);
box-shadow: var(--shadow-l1);
}
.page-home>details[disabled] summary,
.page-home>details.disabled summary {
pointer-events: none;
user-select: none;
}
.page-home>details summary::-webkit-details-marker,
.page-home>details summary::marker {
display: none;
content: "";
}
.page-home summary {
width: calc(100% - 40px);
cursor: pointer;
color: var(--ColorThemes3);
border-radius: var(--border-radius);
font-size: 16px;
font-weight: 300;
padding: 20px;
position: relative;
}
.page-home summary span {
font-weight: 500;
}
.page-home #home-personal-territory-list {
width: 100%;
margin: 0;
display: flex;
flex-wrap: wrap;
flex-direction: row;
align-content: flex-start;
justify-content: center;
overflow-y: auto;
align-items: flex-start;
transition: .3s ease;
}
.page-home .card {
position: relative;
width: 300px;
height: 200px;
background-color: var(--ColorThemes2);
margin: 0px 10px 20px 10px;
overflow: hidden;
cursor: pointer;
border-radius: 10px;
}
@media (max-width: 2300px) {
.page-home .card {
width: calc((100% / 5) - 30px);
}
}
@media (max-width: 1960px) {
.page-home .card {
width: calc((100% / 4) - 30px);
}
}
@media (max-width: 1640px) {
.page-home .card {
width: calc((100% / 3) - 30px);
}
}
@media (max-width: 1280px) {
.page-home .card {
width: calc((100% / 2) - 30px);
}
}
@media (max-width: 650px) {
.page-home .card {
width: 100%;
}
}
@media(hover: hover) {
.page-home .card:hover {
opacity: 0.8;
}
}
.page-home .card>i {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
z-index: 1;
filter: blur(2px);
/* background-repeat: round; */
background-size: cover;
background-position: center;
background-image: url(https://tm.rozenrod.com/web/img/bg.webp);
}
.page-home .card>a {
position: absolute;
width: 100%;
height: 100%;
z-index: 10;
}
.page-home .contents {
position: absolute;
z-index: 2;
background: rgb(64 64 64 / 0.7);
width: 100%;
height: 100%;
font-size: 40px;
font-weight: 500;
color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
.page-home .group {
width: calc(100% - 20px);
max-height: 50px;
border-radius: 7px;
padding: 10px 0;
margin-top: 10px;
display: flex;
background: var(--PrimaryColor);
align-items: center;
flex-direction: column;
justify-content: space-around;
}
.page-home .group>span {
color: #fff;
font-size: 14px;
font-weight: 400;
}
.page-home .info {
width: calc(100% - 20px);
margin-bottom: 10px;
}
.page-home .info>div {
width: 100%;
height: 35px;
margin-top: 5px;
display: flex;
background: var(--ColorThemes0);
align-items: center;
justify-content: center;
font-size: 12px;
color: var(--ColorThemes3);
border-radius: 7px;
position: relative;
overflow: hidden;
}
.page-home .info>div>span {
color: var(--ColorThemes3);
font-size: 14px;
font-weight: 300;
z-index: 2;
}
.page-home .info>div>p {
color: var(--ColorThemes3);
font-size: 14px;
font-weight: 400;
padding: 10px;
z-index: 2;
}

View File

View File

@@ -0,0 +1,6 @@
const Options = {
init: async () => {
let html = await fetch('/lib/pages/options/index.html').then((response) => response.text());
app.innerHTML = html;
}
}

View File

View File

@@ -0,0 +1,250 @@
<div class="page-sheeps">
<div id="block-sheeps-list">
<div class="header">
<h1>Всі вісники</h1>
</div>
<div class="card-profile"></div>
<div class="card-profile"></div>
<div class="card-profile"></div>
<div class="card-profile"></div>
<div class="card-profile"></div>
<div class="card-profile"></div>
<div class="card-profile"></div>
<div class="card-profile"></div>
<div class="card-profile"></div>
<div class="card-profile"></div>
<div class="card-profile"></div>
<div class="card-profile"></div>
</div>
<div id="block-sheep-info">
<div id="sheep-mess">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<path
d="M 25.042969 12 C 20.698969 12 18 15.029297 18 19.904297 C 18 24.104297 20.766812 28.599609 24.882812 28.599609 C 27.167812 28.599609 31 27.369813 31 19.132812 C 31 14.999813 28.494969 12 25.042969 12 z M 39.974609 12 C 35.672609 12 33 14.931437 33 19.648438 C 33 24.104438 34.862391 28.599609 39.025391 28.599609 C 43.603391 28.599609 46 23.922734 46 19.302734 C 46 14.285734 42.876609 12 39.974609 12 z M 25.042969 16 C 26.388969 16 27 17.623812 27 19.132812 C 27 20.776813 26.794812 24.599609 24.882812 24.599609 C 23.428813 24.599609 22 22.274297 22 19.904297 C 22 16.000297 24.132969 16 25.042969 16 z M 39.974609 16 C 41.224609 16 42 17.265734 42 19.302734 C 42 21.906734 40.886391 24.599609 39.025391 24.599609 C 37.594391 24.599609 37 21.375438 37 19.648438 C 37 16.000438 39.084609 16 39.974609 16 z M 13.689453 24 C 9.8134531 24 7 27.465234 7 32.240234 C 7 35.462234 9.0299688 40 13.542969 40 C 17.224969 40 20 36.250297 20 31.279297 C 20 27.061297 17.346453 24 13.689453 24 z M 50.75 24 C 46.94 24 43 27.440219 43 33.199219 C 43 36.541219 45.15 40 48.75 40 C 52.612 40 56 35.477312 56 30.320312 C 56 26.480313 53.939 24 50.75 24 z M 13.689453 28 C 15.514453 28 16 30.061297 16 31.279297 C 16 33.793297 14.852969 36 13.542969 36 C 11.603969 36 11 33.244234 11 32.240234 C 11 29.783234 12.131453 28 13.689453 28 z M 50.75 28 C 51.783 28 52 29.262313 52 30.320312 C 52 33.788312 49.866 36 48.75 36 C 47.514 36 47 34.175219 47 33.199219 C 47 29.652219 49.237 28 50.75 28 z M 31.806641 30.001953 C 29.371641 29.947953 27.296656 31.058937 25.597656 33.335938 C 22.515656 37.450938 21.695953 38.210313 19.376953 39.695312 C 17.528953 40.875312 14.998047 42.492141 14.998047 45.994141 C 14.998047 49.769141 18.164641 52.839844 22.056641 52.839844 C 23.872641 52.839844 25.588266 52.174453 27.697266 51.439453 C 29.071266 52.348453 30.722125 52.839844 32.453125 52.839844 C 34.215125 52.839844 35.869422 52.353125 37.232422 51.453125 C 41.805422 53.496125 44.150719 53.039344 45.636719 52.277344 C 47.314719 51.416344 48.403953 49.800703 48.876953 47.470703 C 49.107953 46.334703 48.997375 45.198781 48.609375 44.175781 C 48.012375 42.602781 46.757453 41.293531 45.064453 40.644531 C 43.137453 39.916531 42.576406 39.753172 41.316406 38.826172 C 39.672406 37.616172 39.015453 35.742422 37.814453 33.607422 C 36.601453 31.449422 34.298641 30.067953 31.806641 30.001953 z M 31.701172 34.001953 C 32.777172 34.029953 33.808125 34.644359 34.328125 35.568359 C 35.480125 37.621359 36.442312 40.205828 38.945312 42.048828 C 40.748312 43.375828 41.894813 43.725812 43.632812 44.382812 C 44.073813 44.550813 44.501812 44.883844 44.757812 45.339844 C 44.966813 45.711844 45.061031 46.164781 44.957031 46.675781 C 44.738031 47.753781 44.3535 48.44175 43.8125 48.71875 C 42.4475 49.41975 39.736125 48.192875 38.578125 47.671875 C 38.187125 47.495875 36.729781 46.582125 35.550781 47.703125 C 34.778781 48.436125 33.679125 48.839844 32.453125 48.839844 C 31.288125 48.839844 30.211922 48.444562 29.419922 47.726562 C 28.893922 47.247562 28.151609 47.085828 27.474609 47.298828 C 25.411609 47.948828 23.441594 48.839844 22.058594 48.839844 C 20.372594 48.839844 19.001953 47.562141 19.001953 45.994141 C 19.001953 44.795141 19.69525 44.240406 21.53125 43.066406 C 24.29525 41.302406 25.514688 40.146469 28.804688 35.730469 C 29.975687 34.161469 30.981172 33.980953 31.701172 34.001953 z"
/>
</svg>
<h1>Виберіть вісника для редагування</h1>
</div>
<form id="sheep-editor" style="display: none; opacity: 0">
<div class="header">
<h1>Інформація про вісника</h1>
<button onclick="Sheeps.editor.close()">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26">
<path
d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"
></path>
</svg>
</button>
</div>
<i id="sheep-editor-icon"></i>
<div class="editor-blocks-inputs" id="editor-blocks-inputs-uuid">
<label>UUID</label>
<input
id="sheep-editor-uuid"
type="text"
name="uuid"
value=""
disabled
style="display: none"
/>
<p id="sheep-editor-uuid-copy" style="cursor: copy !important"></p>
</div>
<div class="editor-blocks-inputs">
<label for="sheep-editor-name">Імʼя</label>
<input id="sheep-editor-name" type="text" name="name" required="" />
</div>
<div class="editor-blocks-inputs">
<label for="sheep-editor-group_id">Група</label>
<select id="sheep-editor-group_id" name="group_id">
<option value="1">Група 1</option>
<option value="2" selected>Група 2</option>
<option value="3">Група 3</option>
<option value="4">Група 4</option>
<option value="5">Група 5</option>
<option value="6">Група 6</option>
<option value="7">Група 7</option>
</select>
</div>
<div class="editor-blocks-inputs">
<label for="sheep-editor-appointment">Призначення</label>
<select id="sheep-editor-appointment" name="appointment">
<option value="lamb" selected>Вісник</option>
<option value="pioneer">Піонер</option>
<option value="attender">Служитель збору</option>
<option value="elder">Старійшина збору</option>
</select>
</div>
<div class="editor-blocks-inputs">
<label for="sheep-editor-mode">Права</label>
<select id="sheep-editor-mode" name="mode">
<option value="sheep" selected>Користувач</option>
<option value="moderator">Модератор</option>
<option value="administrator">Адміністратор</option>
</select>
</div>
<div
class="editor-blocks-inputs"
id="editor-blocks-inputs-uuid-moder"
style="display: none"
>
<label>UUID адміністратора/модератора</label>
<p id="sheep-editor-uuid-moder" style="cursor: copy !important"></p>
</div>
<div
class="editor-blocks-checkbox"
id="sheep-editor-access-moder"
style="display: none"
>
<p for="editor-access">Дозволи модератора</p>
<div>
<div class="checkbox">
<input
name="can_add_sheeps"
class="custom-checkbox"
id="sheep-editor-can_add_sheeps"
type="checkbox"
/>
<label for="sheep-editor-can_add_sheeps"> Create Sheeps </label>
</div>
<div class="checkbox">
<input
name="can_add_territory"
class="custom-checkbox"
id="sheep-editor-can_add_territory"
type="checkbox"
/>
<label for="sheep-editor-can_add_territory">
Create Territory
</label>
</div>
<div class="checkbox">
<input
name="can_manager_territory"
class="custom-checkbox"
id="sheep-editor-can_manager_territory"
type="checkbox"
/>
<label for="sheep-editor-can_manager_territory">
Manager Territory
</label>
</div>
<div class="checkbox">
<input
name="can_add_stand"
class="custom-checkbox"
id="sheep-editor-can_add_stand"
type="checkbox"
/>
<label for="sheep-editor-can_add_stand"> Create Stand </label>
</div>
<div class="checkbox">
<input
name="can_manager_stand"
class="custom-checkbox"
id="sheep-editor-can_manager_stand"
type="checkbox"
/>
<label for="sheep-editor-can_manager_stand"> Manager Stand </label>
</div>
<div class="checkbox">
<input
name="can_add_schedule"
class="custom-checkbox"
id="sheep-editor-can_add_schedule"
type="checkbox"
/>
<label for="sheep-editor-can_add_schedule"> Create Schedule </label>
</div>
</div>
</div>
<div class="editor-blocks-checkbox">
<p for="editor-access">Дозволи вісника</p>
<div>
<div class="checkbox">
<input
name="can_view_schedule"
class="custom-checkbox"
id="sheep-editor-can_view_schedule"
type="checkbox"
/>
<label for="sheep-editor-can_view_schedule"> View Schedule </label>
</div>
<div class="checkbox">
<input
name="can_view_stand"
class="custom-checkbox"
id="sheep-editor-can_view_stand"
type="checkbox"
/>
<label for="sheep-editor-can_view_stand"> View Stand </label>
</div>
<div class="checkbox">
<input
name="can_view_territory"
class="custom-checkbox"
id="sheep-editor-can_view_territory"
type="checkbox"
/>
<label for="sheep-editor-can_view_territory">
View Territory
</label>
</div>
</div>
</div>
<button id="sheep-editor-button" style="display: none">Зберегти</button>
</form>
</div>
<div id="block-sheep-addeds" style="display: none; opacity: 0">
<form id="sheep-addeds">
<div class="header">
<h1>Додавання нового вісника</h1>
<button onclick="Sheeps.addeds.close()" class="close" type="button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26">
<path
d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"
></path>
</svg>
</button>
</div>
<i id="sheep-addeds-icon"></i>
<div class="addeds-blocks-inputs">
<label for="sheep-addeds-name">Імʼя</label>
<input id="sheep-addeds-name" type="text" name="name" required="" />
</div>
<div class="addeds-blocks-inputs">
<label for="sheep-addeds-group_id">Група</label>
<select id="sheep-addeds-group_id" name="group_id" required>
<option value="" selected disabled>Оберіть...</option>
<option value="1">Група 1</option>
<option value="2">Група 2</option>
<option value="3">Група 3</option>
<option value="4">Група 4</option>
<option value="5">Група 5</option>
<option value="6">Група 6</option>
<option value="7">Група 7</option>
</select>
</div>
<div class="addeds-blocks-inputs">
<label for="sheep-addeds-appointment">Призначення</label>
<select id="sheep-addeds-appointment" name="appointment" required>
<option value="lamb" selected>Вісник</option>
<option value="pioneer">Піонер</option>
<option value="attender">Служитель збору</option>
<option value="elder">Старійшина збору</option>
</select>
</div>
<button id="sheep-addeds-button">Додати</button>
</form>
</div>
</div>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,482 @@
.page-sheeps {
width: calc(100% - 18px);
display: flex;
flex-direction: row;
margin: 20px 9px 0 9px;
justify-content: space-between;
position: relative;
}
#block-sheeps-list,
#block-sheep-info {
width: 100%;
margin: 0 10px 15px;
border-radius: 15px;
display: flex;
flex-direction: column;
overflow: hidden;
background: var(--ColorThemes1);
color: var(--ColorThemes3);
border: 1px solid var(--ColorThemes2);
box-shadow: var(--shadow-l1);
transition: all .2s ease 0s;
}
#block-sheep-info {
min-height: calc(100vh - 40px);
max-height: calc(100vh - 40px);
position: sticky;
overflow: auto;
top: 20px;
right: 0;
}
#block-sheeps-list>.header {
min-height: 40px;
width: calc(100% - 20px);
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
background: var(--PrimaryColor);
margin: 10px;
border-radius: 10px;
}
#block-sheeps-list>.header>h1 {
font-size: 16px;
font-weight: 400;
color: var(--PrimaryColorText);
margin-left: 10px;
}
#block-sheeps-list>.header>button {
display: flex;
position: relative;
width: 30px;
height: 30px;
background: var(--ColorThemes0);
margin-right: 5px;
border-radius: 8px;
align-items: center;
justify-content: center;
font-size: 30px;
cursor: pointer;
}
#block-sheeps-list>.header>button>svg {
width: 20px;
height: 20px;
fill: var(--ColorThemes3);
transform: rotate(45deg);
}
#block-sheeps-list>.card-profile {
width: calc(100% - 30px);
min-height: 100px;
background-color: var(--ColorThemes2);
border: 1px solid var(--ColorThemes0);
box-shadow: var(--shadow-l1);
border-radius: 10px;
margin: 10px;
display: flex;
flex-direction: row;
align-items: center;
padding: 5px;
cursor: pointer;
}
#block-sheeps-list>.card-profile>img,
#block-sheeps-list>.card-profile>svg {
width: 65px;
min-width: 65px;
height: 65px;
margin: 10px 15px 10px 10px;
fill: var(--PrimaryColor);
}
#block-sheeps-list>.card-profile>.info {
display: flex;
flex-direction: column;
height: 90px;
justify-content: space-between;
position: relative;
width: calc(100% - 95px);
}
#block-sheeps-list>.card-profile>.info>.text>h1 {
font-size: 16px;
color: var(--ColorThemes3);
font-weight: 400;
}
#block-sheeps-list>.card-profile>.info>.text>h2 {
font-size: 12px;
color: var(--ColorThemes3);
font-weight: 400;
opacity: 0.8;
}
#block-sheeps-list>.card-profile>.info>.access {
display: flex;
overflow-x: auto;
overflow-y: hidden;
max-width: 100%;
padding-bottom: 4px;
height: 30px;
}
#block-sheeps-list>.card-profile>.info>.access>b {
padding: 2px 5px;
border-radius: 5px;
background: var(--PrimaryColor);
color: var(--PrimaryColorText);
margin-right: 5px;
white-space: nowrap;
font-size: 13px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
#block-sheep-info>#sheep-mess {
width: 200px;
height: 200px;
display: flex;
flex-direction: column;
align-items: center;
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -100px;
justify-content: center;
opacity: 0.6;
transition: all .2s ease 0s;
z-index: 1;
}
#block-sheep-info>#sheep-mess>svg {
width: 100px;
height: 100px;
fill: var(--ColorThemes3);
}
#block-sheep-info>#sheep-mess>h1 {
font-size: 20px;
color: var(--ColorThemes3);
font-weight: 400;
text-align: center;
}
#block-sheep-info>#sheep-editor {
display: flex;
padding: 10px;
flex-direction: column;
align-items: center;
transition: all .3s ease 0s;
z-index: 2;
}
#block-sheep-info>#sheep-editor>.header {
display: none;
min-height: 40px;
width: 100%;
flex-direction: row;
align-items: center;
justify-content: space-between;
background: var(--ColorThemes3);
margin: 0 0 10px 0;
border-radius: 10px;
}
#block-sheep-info>#sheep-editor>.header>h1 {
font-size: 16px;
font-weight: 400;
color: var(--ColorThemes0);
margin-left: 10px;
}
#block-sheep-info>#sheep-editor>.header>button {
display: flex;
position: relative;
width: 30px;
height: 30px;
background: var(--ColorThemes0);
margin-right: 5px;
border-radius: 8px;
align-items: center;
justify-content: center;
font-size: 30px;
cursor: pointer;
}
#block-sheep-info>#sheep-editor>.header>button>svg {
width: 20px;
height: 20px;
fill: var(--ColorThemes3);
}
#block-sheep-info>#sheep-editor>i>svg {
width: 100px;
height: 100px;
fill: var(--PrimaryColor);
}
#block-sheep-info>#sheep-editor>.editor-blocks-inputs {
width: 100%;
display: flex;
margin: 10px 0;
align-items: flex-start;
flex-direction: column;
}
#block-sheep-info>#sheep-editor>.editor-blocks-inputs label {
display: flex;
justify-content: center;
flex-direction: column;
font-size: 12px;
font-weight: 500;
margin-bottom: 5px;
}
#block-sheep-info>#sheep-editor>.editor-blocks-inputs input {
width: calc(100% - 10px);
min-width: 140px;
padding: 0 5px;
border-radius: 6px;
height: 30px;
background: var(--ColorThemes0);
color: var(--ColorThemes3);
}
#block-sheep-info>#sheep-editor>.editor-blocks-inputs select {
width: 100%;
min-width: 140px;
padding: 0 5px;
border-radius: 6px;
height: 30px;
background-color: var(--ColorThemes0);
color: var(--ColorThemes3);
}
#block-sheep-info>#sheep-editor>.editor-blocks-inputs p {
display: flex;
width: calc(100% - 10px);
min-width: 140px;
font-size: 14px;
padding: 0 5px;
border-radius: 6px;
height: 30px;
background: var(--ColorThemes0);
color: var(--ColorThemes3);
align-items: center;
cursor: copy;
}
#block-sheep-info>#sheep-editor>.editor-blocks-checkbox {
width: 100%;
display: flex;
margin: 10px 0;
align-items: flex-start;
flex-direction: column;
}
#block-sheep-info>#sheep-editor>.editor-blocks-checkbox>p {
display: flex;
justify-content: center;
flex-direction: column;
font-size: 12px;
font-weight: 500;
margin-bottom: 5px;
}
#block-sheep-info>#sheep-editor>.editor-blocks-checkbox>div {
background: var(--ColorThemes0);
border-radius: 6px;
width: calc(100% - 15px);
padding: 0 5px 0 10px;
}
#block-sheep-info>#sheep-editor>.editor-blocks-checkbox>div>.checkbox {
margin: 10px 0;
width: 100%;
font-size: 14px;
}
#block-sheep-info>#sheep-editor>.editor-blocks-checkbox>div>.checkbox>.custom-checkbox+label {
width: 100%;
display: flex;
align-items: center;
user-select: none;
flex-direction: row-reverse;
justify-content: space-between;
}
#block-sheep-info>#sheep-editor>button {
border-radius: 6px;
background: var(--PrimaryColor);
color: var(--PrimaryColorText);
width: 100%;
height: 40px;
font-size: 14px;
font-weight: 400;
margin: 20px 0 0 0;
text-transform: uppercase;
}
#block-sheep-addeds {
width: 100%;
height: fit-content;
margin: 0 10px 15px;
border-radius: 15px;
display: flex;
flex-direction: column;
overflow: hidden;
background: var(--ColorThemes1);
color: var(--ColorThemes3);
border: 1px solid var(--ColorThemes2);
box-shadow: var(--shadow-l1);
transition: all .2s ease 0s;
}
#block-sheep-addeds>#sheep-addeds {
display: flex;
padding: 10px;
flex-direction: column;
align-items: center;
transition: all .3s ease 0s;
}
#block-sheep-addeds>#sheep-addeds>div {
width: 100%;
display: flex;
justify-content: space-between;
}
#block-sheep-addeds>#sheep-addeds>.header {
min-height: 40px;
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
background: var(--ColorThemes3);
margin: 0 0 10px 0;
border-radius: 10px;
}
#block-sheep-addeds>#sheep-addeds>.header>h1 {
font-size: 16px;
font-weight: 400;
color: var(--ColorThemes0);
margin-left: 10px;
}
#block-sheep-addeds>#sheep-addeds>.header>button {
display: flex;
position: relative;
width: 30px;
height: 30px;
background: var(--ColorThemes0);
margin-right: 5px;
border-radius: 8px;
align-items: center;
justify-content: center;
font-size: 30px;
cursor: pointer;
}
#block-sheep-addeds>#sheep-addeds>.header>button>svg {
width: 20px;
height: 20px;
fill: var(--ColorThemes3);
}
#block-sheep-addeds>#sheep-addeds>i>svg {
width: 100px;
height: 100px;
fill: var(--PrimaryColor);
}
#block-sheep-addeds>#sheep-addeds>.addeds-blocks-inputs {
width: 100%;
display: flex;
margin: 10px 0;
align-items: flex-start;
flex-direction: column;
}
#block-sheep-addeds>#sheep-addeds>.addeds-blocks-inputs label {
display: flex;
justify-content: center;
flex-direction: column;
font-size: 12px;
font-weight: 500;
margin-bottom: 5px;
}
#block-sheep-addeds>#sheep-addeds>.addeds-blocks-inputs input {
width: calc(100% - 10px);
min-width: 140px;
padding: 0 5px;
border-radius: 6px;
height: 30px;
background: var(--ColorThemes0);
color: var(--ColorThemes3);
}
#block-sheep-addeds>#sheep-addeds>.addeds-blocks-inputs select {
width: 100%;
min-width: 140px;
padding: 0 5px;
border-radius: 6px;
height: 30px;
background-color: var(--ColorThemes0);
color: var(--ColorThemes3);
}
#block-sheep-addeds>#sheep-addeds>button {
border-radius: 6px;
background: var(--PrimaryColor);
color: var(--PrimaryColorText);
width: 100%;
height: 40px;
font-size: 14px;
font-weight: 400;
margin: 20px 0 0 0;
text-transform: uppercase;
}
@media (min-width: 1001px),
(min-height: 541px) {
#block-sheeps-list,
#block-sheep-info {
opacity: 1 !important;
}
}
@media (max-width: 1000px),
(max-height: 540px) {
#block-sheeps-list {
display: none;
}
#block-sheep-info {
display: none;
min-height: fit-content;
}
#block-sheep-info>#sheep-editor>.header {
display: flex;
}
}
/* @media (min-height: 600px) and (max-height: 700px) {
#block-sheep-info>#sheep-editor>i>svg {
display: none;
}
} */

View File

@@ -0,0 +1,4 @@
<div class="page-stand">
<label for="dateSelect">Виберіть дату:</label>
<select id="dateSelect"></select>
</div>

View File

@@ -0,0 +1,38 @@
const Stand = {
init: async () => {
let html = await fetch('/lib/pages/stand/index.html').then((response) => response.text());
app.innerHTML = html;
let listDate = [1, 4];
function generateAvailableDates() {
let select = document.getElementById("dateSelect");
select.innerHTML = "";
let today = new Date();
today.setHours(0, 0, 0, 0);
let months = [today.getMonth(), today.getMonth() + 1];
let year = today.getFullYear();
months.forEach(month => {
let date = new Date(year, month, 1);
while (date.getMonth() === month) {
if (date >= today) {
let day = date.getDay();
if (listDate.includes(day)) {
let option = document.createElement("option");
option.value = date.toISOString().split("T")[0];
option.textContent = date.toLocaleDateString("uk-UA", {
weekday: "long", year: "numeric", month: "long", day: "numeric"
});
select.appendChild(option);
}
}
date.setDate(date.getDate() + 1);
}
});
}
generateAvailableDates();
}
}

View File

@@ -0,0 +1,20 @@
.page-stand {
width: calc(100% - 40px);
display: flex;
flex-direction: column;
margin: 20px 20px 0 20px;
}
.page-stand select {
width: 100%;
min-width: 140px;
padding: 0 5px;
border-radius: 6px;
height: 30px;
background-color: var(--ColorThemes1);
color: var(--ColorThemes3);
border: 1px solid var(--ColorThemes2);
margin: 10px 0;
box-shadow: var(--shadow-l1);
font-size: 14px;
}

View File

@@ -0,0 +1,39 @@
<div class="page-territory">
<div class="buttons-list">
<button onclick="Rotation()" id="rotationButton" style="display: none;">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<path
d="M16.5 25.5c-.52.893-1.476 1.5-2.584 1.5-1.657 0-3-1.343-3-3s1.343-3 3-3c1.108 0 2.064.607 2.584 1.5H23v-11C23 8.468 20.533 6 17.5 6h-6C8.467 6 6 8.468 6 11.5v25c0 3.032 2.467 5.5 5.5 5.5h6c3.033 0 5.5-2.468 5.5-5.5v-11H16.5zM36.5 6h-6C27.467 6 25 8.468 25 11.5v11h7.879l-1.439-1.439c-.586-.586-.586-1.535 0-2.121s1.535-.586 2.121 0l4 4c.586.586.586 1.535 0 2.121l-4 4C33.268 29.354 32.884 29.5 32.5 29.5s-.768-.146-1.061-.439c-.586-.586-.586-1.535 0-2.121l1.439-1.439H25v11c0 3.032 2.467 5.5 5.5 5.5h6c3.033 0 5.5-2.468 5.5-5.5v-25C42 8.468 39.533 6 36.5 6z"
/>
</svg>
<span id="rotationButton-title">Провести ротацію</span>
</button>
<a href="/constructor" data-route id="constructorButton" style="display: none;">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<path
d="M 14.5 4 C 12.015 4 10 6.015 10 8.5 L 10 39.5 C 10 41.985 12.015 44 14.5 44 L 22.042969 44 C 22.079969 43.749 22.138516 43.502672 22.228516 43.263672 L 22.283203 43.285156 C 22.353203 42.961156 23.236422 40.161109 23.982422 37.787109 C 24.272422 36.865109 24.779891 36.029703 25.462891 35.345703 L 33.904297 27 L 27.5 27 C 26.672 27 26 26.328 26 25.5 L 26 16 L 38 16 L 38 23.054688 C 38.72 22.587688 39.4975 22.254422 40.3125 22.107422 C 40.5365 22.067422 40.769 22.062922 41 22.044922 L 41 14.5 C 41 13.672 40.328 13 39.5 13 L 34 13 L 34 8.5 C 34 6.015 31.985 4 29.5 4 L 14.5 4 z M 30.5 18 A 1.50015 1.50015 0 1 0 30.5 21 L 33.5 21 A 1.50015 1.50015 0 1 0 33.5 18 L 30.5 18 z M 41.498047 24 C 41.224047 24.001 40.946969 24.025172 40.667969 24.076172 C 39.783969 24.235172 38.939563 24.696156 38.226562 25.410156 L 26.427734 37.208984 C 26.070734 37.565984 25.807969 38.011141 25.667969 38.494141 L 24.097656 43.974609 C 24.025656 44.164609 23.993 44.365406 24 44.566406 C 24.013 44.929406 24.155594 45.288406 24.433594 45.566406 C 24.710594 45.843406 25.067688 45.986 25.429688 46 C 25.630688 46.007 25.834391 45.975344 26.025391 45.902344 L 31.505859 44.332031 C 31.988859 44.192031 32.431062 43.930266 32.789062 43.572266 L 44.589844 31.773438 C 45.303844 31.060437 45.764828 30.216031 45.923828 29.332031 C 45.973828 29.053031 45.997047 28.775953 45.998047 28.501953 C 46.001047 27.307953 45.540687 26.179312 44.679688 25.320312 C 43.820687 24.460313 42.692047 23.998 41.498047 24 z M 22 35 C 22.828 35 23.5 35.672 23.5 36.5 C 23.5 37.328 22.828 38 22 38 C 21.172 38 20.5 37.328 20.5 36.5 C 20.5 35.672 21.172 35 22 35 z"
/>
</svg>
<span>Конструктор</span>
</a>
</div>
<div class="list-controls"></div>
<details open>
<summary>
<span>Багатоквартирні будинки</span>
</summary>
<div id="list-house"></div>
</details>
<details open>
<summary>
<span>Житлові райони</span>
</summary>
<div id="list-homestead"></div>
</details>
</div>

View File

@@ -0,0 +1,130 @@
const Territory = {
init: async () => {
let html = await fetch('/lib/pages/territory/index.html').then((response) => response.text());
app.innerHTML = html;
if (USER.administrator.uuid) document.getElementById('rotationButton').style.display = "";
if (USER.administrator.uuid || (USER.moderator.uuid && USER.moderator.can_add_territory)) document.getElementById("constructorButton").style.display = "";
Territory.house.setHTML();
Territory.homestead.setHTML();
},
house: {
loadAPI: async function () {
let uuid = localStorage.getItem("uuid");
const URL = `${CONFIG.api}houses/list`;
return await fetch(URL, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
}).then((response) => response.json());
},
setHTML: async function () {
let list = await Territory.house.loadAPI();
list.sort((a, b) => b.id - a.id);
console.log(list);
let block_house = document.getElementById('list-house')
block_house.innerHTML = "";
for (let i = 0; i < list.length; i++) {
const element = list[i];
let progress = ((element.entrance.working / element.entrance.quantity) * 100);
let pageURL = () => {
if (USER.administrator.uuid || (USER.moderator.uuid && USER.moderator.can_manager_territory)) return `/territory/manager/house/${element.id}`;
else return `/territory/card/house/${element.id}`
}
block_house.innerHTML += `
<div class="card">
<i style="background-image: url(https://sheep-service.com/cards/house/T${element.id}.webp);"></i>
<div class="contents">
<div class="group" style="background: ${colorGroup(element.group_id)}">
<span>Група №${element.group_id}</span>
</div>
<div class="info">
<div>
<div class="progress" style="width: ${progress}%"></div>
<span>Вільні під'їзди:</span>
<p>${element.entrance.quantity - element.entrance.working} / ${element.entrance.quantity}</p>
</div>
<div>
<p>${element.title} ${element.number}</p>
</div>
</div>
</div>
<a href="${pageURL()}" data-route></a>
</div>
`;
}
}
},
homestead: {
loadAPI: async function () {
let uuid = localStorage.getItem("uuid");
const URL = `${CONFIG.api}homestead/list`;
return await fetch(URL, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
}).then((response) => response.json());
},
setHTML: async function () {
let list = await Territory.homestead.loadAPI();
list.sort((a, b) => b.id - a.id);
console.log(list);
let block_homestead = document.getElementById('list-homestead')
block_homestead.innerHTML = "";
for (let i = 0; i < list.length; i++) {
const element = list[i];
let block_history = () => {
if (element.working) {
return `
<div>
<div class="progress" style="width: 100%"></div>
<p>${element.history.name}</p>
</div>
`
}
return ''
}
let pageURL = () => {
if (USER.administrator.uuid || (USER.moderator.uuid && USER.moderator.can_manager_territory)) return `/territory/manager/homestead/${element.id}`;
else return `/territory/card/homestead/${element.id}`
}
block_homestead.innerHTML += `
<div class="card">
<i style="background-image: url(https://sheep-service.com/cards/homestead/H${element.id}.webp);"></i>
<div class="contents">
<div class="group" style="background: ${colorGroup(element.group_id)}">
<span>Група №${element.group_id}</span>
</div>
<div class="info">
${block_history()}
<div>
<p>${element.title} ${element.number}</p>
</div>
</div>
</div>
<a href="${pageURL()}" data-route></a>
</div>
`;
}
}
}
}

View File

@@ -0,0 +1,247 @@
.page-territory {
width: calc(100% - 40px);
display: flex;
flex-direction: column;
margin: 20px 20px 0 20px;
}
.page-territory>.buttons-list {
padding: 10px;
margin-bottom: 20px;
background: var(--ColorThemes1);
color: var(--ColorThemes3);
border: 1px solid var(--ColorThemes2);
box-shadow: var(--shadow-l1);
border-radius: 15px;
overflow: auto;
display: flex;
}
.page-territory>.buttons-list>button,
.page-territory>.buttons-list>a {
cursor: pointer;
border-radius: 10px;
padding: 0 10px;
margin-right: 20px;
min-width: fit-content;
min-height: 40px;
background: var(--PrimaryColor);
display: flex;
align-items: center;
justify-content: center;
}
.page-territory>.buttons-list>button>span,
.page-territory>.buttons-list>a>span {
color: var(--PrimaryColorText);
font-size: 14px;
font-weight: normal;
}
.page-territory>.buttons-list>button>svg,
.page-territory>.buttons-list>a>svg {
width: 20px;
height: 20px;
fill: var(--PrimaryColorText);
margin-right: 10px;
}
.page-territory details {
border-radius: 15px;
width: 100%;
display: flex;
flex-direction: column;
align-items: stretch;
margin-bottom: 20px;
background: var(--ColorThemes1);
color: var(--ColorThemes3);
border: 1px solid var(--ColorThemes2);
box-shadow: var(--shadow-l1);
}
.page-territory>details[disabled] summary,
.page-territory>details.disabled summary {
pointer-events: none;
user-select: none;
}
.page-territory>details summary::-webkit-details-marker,
.page-territory>details summary::marker {
display: none;
content: "";
}
.page-territory summary {
width: calc(100% - 40px);
cursor: pointer;
color: var(--ColorThemes3);
border-radius: var(--border-radius);
font-size: 16px;
font-weight: 300;
padding: 20px;
position: relative;
}
.page-territory summary span {
font-weight: 500;
}
.page-territory #list-house,
.page-territory #list-homestead {
width: 100%;
margin: 0;
display: flex;
flex-wrap: wrap;
flex-direction: row;
align-content: flex-start;
justify-content: center;
overflow-y: auto;
align-items: flex-start;
transition: .3s ease;
}
.page-territory .card {
position: relative;
width: 300px;
height: 200px;
background-color: var(--ColorThemes2);
margin: 0px 10px 20px 10px;
overflow: hidden;
cursor: pointer;
border-radius: 10px;
}
@media (max-width: 2300px) {
.page-territory .card {
width: calc((100% / 5) - 40px);
}
}
@media (max-width: 1960px) {
.page-territory .card {
width: calc((100% / 4) - 40px);
}
}
@media (max-width: 1640px) {
.page-territory .card {
width: calc((100% / 3) - 40px);
}
}
@media (max-width: 1280px) {
.page-territory .card {
width: calc((100% / 2) - 40px);
}
}
@media (max-width: 650px) {
.page-territory .card {
width: 100%;
}
}
@media(hover: hover) {
.page-territory .card:hover {
opacity: 0.8;
}
}
.page-territory .card>i {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
z-index: 1;
filter: blur(2px);
/* background-repeat: round; */
background-size: cover;
background-position: center;
background-image: url(https://tm.rozenrod.com/web/img/bg.webp);
}
.page-territory .card>a {
position: absolute;
width: 100%;
height: 100%;
z-index: 10;
}
.page-territory .contents {
position: absolute;
z-index: 2;
background: rgb(64 64 64 / 0.7);
width: 100%;
height: 100%;
font-size: 40px;
font-weight: 500;
color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
.page-territory .group {
width: calc(100% - 20px);
max-height: 50px;
border-radius: 7px;
padding: 10px 0;
margin-top: 10px;
display: flex;
background: var(--PrimaryColor);
align-items: center;
flex-direction: column;
justify-content: space-around;
}
.page-territory .group>span {
color: #fff;
font-size: 14px;
font-weight: 400;
}
.page-territory .info {
width: calc(100% - 20px);
margin-bottom: 10px;
}
.page-territory .info>div {
width: 100%;
height: 35px;
margin-top: 5px;
display: flex;
background: var(--ColorThemes0);
align-items: center;
justify-content: center;
font-size: 12px;
color: var(--ColorThemes3);
border-radius: 7px;
position: relative;
overflow: hidden;
}
.page-territory .progress {
background: var(--PrimaryColor);
height: 100%;
position: absolute;
z-index: 1;
left: 0;
}
.page-territory .info>div>span {
color: var(--ColorThemes3);
font-size: 14px;
font-weight: 300;
z-index: 2;
}
.page-territory .info>div>p {
color: var(--ColorThemes3);
font-size: 14px;
font-weight: 400;
padding: 10px;
z-index: 2;
}

View File

@@ -0,0 +1,75 @@
<div class="page-territory_manager">
<div id="territory-info">
<div class="territory-info-image" id="CardPicture">
<img id="info-picture" src="" alt="" style="display: none" />
<div id="map_territory_manager"></div>
<div class="menu-picture">
<a id="menu-picture-error" title="Зображення не знайдено!">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30" style="fill: #c14d4d;">
<path
d="M 3.7070312 2.2929688 L 2.2929688 3.7070312 L 26.292969 27.707031 L 27.707031 26.292969 L 26.375 24.960938 C 27.299776 24.784872 28 23.976233 28 23 L 28 7 C 28 5.895 27.105 5 26 5 L 6.4140625 5 L 3.7070312 2.2929688 z M 2.1367188 6.2851562 C 2.0517188 6.5071563 2 6.747 2 7 L 2 23 C 2 24.105 2.895 25 4 25 L 20.851562 25 L 17.851562 22 L 5 22 L 5 15 L 7.2890625 12.710938 C 7.5140625 12.485938 7.7747812 12.317219 8.0507812 12.199219 L 2.1367188 6.2851562 z M 23 8 C 24.105 8 25 8.895 25 10 C 25 11.105 24.105 12 23 12 C 21.895 12 21 11.105 21 10 C 21 8.895 21.895 8 23 8 z M 19 14.001953 C 19.61925 14.001953 20.238437 14.238437 20.710938 14.710938 L 25 19 L 25 22 L 23.414062 22 L 16.707031 15.292969 L 17.289062 14.710938 C 17.761563 14.238437 18.38075 14.001953 19 14.001953 z"
/>
</svg>
</a>
<a id="menu-picture-ok" style="display: none;" title="Зображення знайдено" target="_blank">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30" style="fill: #8BC34A;">
<path
d="M 4 5 C 2.895 5 2 5.895 2 7 L 2 23 C 2 24.105 2.895 25 4 25 L 26 25 C 27.105 25 28 24.105 28 23 L 28 7 C 28 5.895 27.105 5 26 5 L 4 5 z M 23 8 C 24.105 8 25 8.895 25 10 C 25 11.105 24.105 12 23 12 C 21.895 12 21 11.105 21 10 C 21 8.895 21.895 8 23 8 z M 9 13.001953 C 9.61925 13.001953 10.238437 13.238437 10.710938 13.710938 L 13.972656 16.972656 L 15 18 L 16.15625 19.15625 C 16.57825 19.57825 17.259641 19.574344 17.681641 19.152344 C 18.104641 18.730344 18.104641 18.044094 17.681641 17.621094 L 16.529297 16.470703 L 17.289062 15.710938 C 18.234063 14.765937 19.765937 14.765937 20.710938 15.710938 L 25 20 L 25 22 L 5 22 L 5 16 L 7.2890625 13.710938 C 7.7615625 13.238437 8.38075 13.001953 9 13.001953 z"
/>
</svg>
</a>
<button title="Створити нове зображення" onclick="Territory_Manager.getScreen()">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"> <path d="M 22.828125 3 C 22.316375 3 21.804562 3.1954375 21.414062 3.5859375 L 19 6 L 24 11 L 26.414062 8.5859375 C 27.195062 7.8049375 27.195062 6.5388125 26.414062 5.7578125 L 24.242188 3.5859375 C 23.851688 3.1954375 23.339875 3 22.828125 3 z M 17 8 L 5.2597656 19.740234 C 5.2597656 19.740234 6.1775313 19.658 6.5195312 20 C 6.8615312 20.342 6.58 22.58 7 23 C 7.42 23.42 9.6438906 23.124359 9.9628906 23.443359 C 10.281891 23.762359 10.259766 24.740234 10.259766 24.740234 L 22 13 L 17 8 z M 4 23 L 3.0566406 25.671875 A 1 1 0 0 0 3 26 A 1 1 0 0 0 4 27 A 1 1 0 0 0 4.328125 26.943359 A 1 1 0 0 0 4.3378906 26.939453 L 4.3632812 26.931641 A 1 1 0 0 0 4.3691406 26.927734 L 7 26 L 5.5 24.5 L 4 23 z"/></svg>
</button>
</div>
</div>
<div class="territory-info-text">
<h1>Вулиця:</h1>
<h2 id="info-title">--</h2>
</div>
<div class="territory-info-text">
<h1>Номер:</h1>
<h2 id="info-number">--</h2>
</div>
<div class="territory-info-text">
<h1>Населений пункт:</h1>
<h2 id="info-settlement">--</h2>
</div>
<div class="territory-info-text">
<textarea
name="info-description"
id="info-description"
placeholder="Примітка"
></textarea>
</div>
<a id="editor_button" style="display: none" data-route>Змінити територію</a>
</div>
<div id="territory-entrance"></div>
</div>
<div id="territory-new" style="display: none; opacity: 0">
<div class="mess">
<span>Налаштування</span>
<select id="new-worker-name" name="new-worker-name" required="">
<option value="" selected="" disabled="">Оберіть...</option>
</select>
<div>
<button onclick="Territory_Manager.mess.close()">Закрити</button>
<button
id="new-worker-button"
onclick="Territory_Manager.newWorker()"
style="background: var(--PrimaryColor); color: var(--PrimaryColorText)"
>
Призначити
</button>
</div>
</div>
</div>

View File

@@ -0,0 +1,506 @@
let map_territory, type_territory;
const Territory_Manager = {
init: async (type, id) => {
let html = await fetch('/lib/pages/territory_manager/index.html').then((response) => response.text());
app.innerHTML = html;
type_territory = type;
let sheeps_list = [];
if (Sheeps.sheeps_list.list.length == 0) {
sheeps_list = await Sheeps.sheeps_list.loadAPI();
} else {
sheeps_list = Sheeps.sheeps_list.list;
}
let editor_button = document.getElementById('editor_button');
if (USER.administrator.uuid || (USER.moderator.uuid && USER.moderator.can_add_territory)){
editor_button.style.display = "";
editor_button.setAttribute("href", `/territory/editor/${type}/${id}`)
}
await Territory_Manager.info.setHTML(type, id);
Territory_Manager.entrances.setHTML(type, id);
for (let i = 0; i < sheeps_list.length; i++) {
const element = sheeps_list[i];
if (Territory_Manager.info.list.group_id == element.group_id) {
document.getElementById('new-worker-name').innerHTML += `
<option value="${element.name}">${element.name}</option>
`;
}
}
},
info: {
list: {},
loadAPI: async (url) => {
let uuid = localStorage.getItem("uuid");
Territory_Manager.info.list = await fetch(url, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
}).then((response) => response.json());
return Territory_Manager.info.list;
},
setHTML: async (type, id) => {
if (type == "house") {
let url = `${CONFIG.api}house/${id}`;
let data = await Territory_Manager.info.loadAPI(url);
Territory_Manager.map(type, data);
let info_picture = document.getElementById('info-picture');
let info_title = document.getElementById('info-title');
let info_number = document.getElementById('info-number');
let info_settlement = document.getElementById('info-settlement');
let info_description = document.getElementById('info-description');
info_picture.addEventListener("click", (event) => {
let state = info_picture.getAttribute('data-state')
if (state == 'active') info_picture.setAttribute('data-state', '')
else info_picture.setAttribute('data-state', 'active')
});
info_picture.setAttribute("src", ``);
info_title.innerText = data.title;
info_number.innerText = data.number;
info_settlement.innerText = data.settlement;
info_description.value = data.description;
} else if (type == "homestead") {
let url = `${CONFIG.api}homestead/${id}`;
let data = await Territory_Manager.info.loadAPI(url);
Territory_Manager.map(type, data);
let info_picture = document.getElementById('info-picture');
let info_title = document.getElementById('info-title');
let info_number = document.getElementById('info-number');
let info_settlement = document.getElementById('info-settlement');
let info_description = document.getElementById('info-description');
info_picture.addEventListener("click", (event) => {
let state = info_picture.getAttribute('data-state')
if (state == 'active') info_picture.setAttribute('data-state', '')
else info_picture.setAttribute('data-state', 'active')
});
info_picture.setAttribute("src", ``);
info_title.innerText = data.title;
info_number.innerText = data.number;
info_settlement.innerText = data.settlement;
info_description.value = data.description;
}
urlImage = `https://sheep-service.com/cards/${type}/${type == "house" ? "T" : "H"}${id}.webp`;
const checkImage = await fetch(urlImage);
if(checkImage.ok) {
document.getElementById('menu-picture-error').style.display = 'none';
document.getElementById('menu-picture-ok').style.display = '';
document.getElementById('menu-picture-ok').setAttribute("href", urlImage);
} else {
document.getElementById('menu-picture-error').style.display = '';
document.getElementById('menu-picture-ok').style.display = 'none';
}
}
},
entrances: {
list: [],
loadAPI: async (url) => {
let uuid = localStorage.getItem("uuid");
Territory_Manager.entrances.list = await fetch(url, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
}).then((response) => response.json());
return Territory_Manager.entrances.list;
},
setHTML: async (type, id) => {
if (type == "house") {
let url = `${CONFIG.api}house/${id}/entrances`;
let listEntrances = await Territory_Manager.entrances.loadAPI(url);
document.getElementById('territory-entrance').innerHTML = "";
for (let i = 0; i < listEntrances.length; i++) {
const element = listEntrances[i];
let name = () => {
if (element.history.name == "Групова")
return `<p>${element.history.name + " " + element.history.group_id}</p>`;
else {
let sheeps_list = Sheeps.sheeps_list.list;
let filtered = sheeps_list.filter(item => item.group_id === Territory_Manager.info.list.group_id);
let sheep = filtered.find(item => item.name === element.history.name);
return `<a href="/sheeps/${sheep.uuid}" data-route="">${element.history.name}</a>`;
}
}
if (element.working) {
document.getElementById('territory-entrance').innerHTML += `
<div class="entrance" data-state="working">
<div id="title">
<h1>${element.title}</h1>
<a href="/territory/card/${type}/${id}" title="Редактор квартир" data-route>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><path d="M 12.5 6 C 8.9280619 6 6 8.9280619 6 12.5 L 6 35.5 C 6 39.071938 8.9280619 42 12.5 42 L 35.5 42 C 39.071938 42 42 39.071938 42 35.5 L 42 12.5 C 42 8.9280619 39.071938 6 35.5 6 L 12.5 6 z M 12.5 9 L 14 9 L 14 15 L 9 15 L 9 12.5 C 9 10.549938 10.549938 9 12.5 9 z M 17 9 L 35.5 9 C 37.450062 9 39 10.549938 39 12.5 L 39 15 L 17 15 L 17 9 z M 9 18 L 14 18 L 14 23 L 9 23 L 9 18 z M 17 18 L 39 18 L 39 23 L 17 23 L 17 18 z M 9 26 L 14 26 L 14 31 L 9 31 L 9 26 z M 17 26 L 39 26 L 39 31 L 17 31 L 17 26 z M 9 34 L 14 34 L 14 39 L 12.5 39 C 10.549938 39 9 37.450062 9 35.5 L 9 34 z M 17 34 L 39 34 L 39 35.5 C 39 37.450062 37.450062 39 35.5 39 L 17 39 L 17 34 z"/></svg>
</a>
</div>
<div>
<h1>Територію опрацьовує: </h1>
${name()}
</div>
<div>
<h1>Територія видана: </h1>
<h2>${formattedDate(element.history.date.start)}</h2>
</div>
<div>
<h1>Варто забрати: </h1>
<h2>${formattedDate(element.history.date.end) ?? formattedDate(element.history.date.start + (1000 * 2629743 * 4))}</h2>
</div>
<div class="edit_working">
<button onclick="Territory_Manager.endWorker('${type}', ${id}, ${element.history.id})" id="end-working-button" style="color: #121214;background: #c14d4d;">Забрати</button>
<button onclick="Territory_Manager.share('${type}', ${i})">Відправити посилання</button>
</div>
</div>
`;
} else {
document.getElementById('territory-entrance').innerHTML += `
<div class="entrance">
<div id="title">
<h1>${element.title}</h1>
</div>
<div>
<h1>Територія не опрацьовується</h1>
</div>
<div>
<h1>Останнє опрацювання: </h1>
<h2>${formattedDate(element.history.date.end) ?? "..."}</h2>
</div>
<div class="edit">
<button onclick="Territory_Manager.newWorker('${type}',${id}, ${i}, 'Групова')" id="group-working-button" style="color: var(--ColorThemes0);background: var(--ColorThemes3);">Призначити груповою</button>
<button onclick="Territory_Manager.mess.open('${type}', ${id}, ${i})">Призначити вісника</button>
</div>
</div>
`;
}
console.log(element);
}
} else if (type == "homestead") {
let url = `${CONFIG.api}homestead/${id}`;
let element = await Territory_Manager.entrances.loadAPI(url);
document.getElementById('territory-entrance').innerHTML = "";
let name = () => {
if (element.history.name == "Групова")
return `<p>${element.history.name + " " + element.history.group_id}</p>`;
else
return `<a href="/sheeps/${element.history.name}" data-route="">${element.history.name}</a>`;
}
if (element.working) {
document.getElementById('territory-entrance').innerHTML += `
<div class="entrance" data-state="working">
<div>
<h1>Територію опрацьовує: </h1>
${name()}
</div>
<div>
<h1>Територія видана: </h1>
<h2>${formattedDate(element.history.date.start)}</h2>
</div>
<div>
<h1>Варто забрати: </h1>
<h2>${formattedDate(element.history.date.end) ?? formattedDate(element.history.date.start + (1000 * 2629743 * 4))}</h2>
</div>
<div class="edit_working">
<button onclick="Territory_Manager.endWorker('${type}', ${id}, ${element.history.id})" id="end-working-button" style="color: #121214;background: #c14d4d;">Забрати</button>
<button onclick="Territory_Manager.share('${type}', ${i})">Відправити посилання</button>
</div>
</div>
`;
} else {
document.getElementById('territory-entrance').innerHTML += `
<div class="entrance">
<div>
<h1>Територія не опрацьовується</h1>
</div>
<div>
<h1>Останнє опрацювання: </h1>
<h2>${formattedDate(element.history.date.end) ?? "..."}</h2>
</div>
<div class="edit">
<button onclick="Territory_Manager.newWorker('${type}',${id}, ${i}, 'Групова')" id="group-working-button" style="color: var(--ColorThemes0);background: var(--ColorThemes3);">Призначити груповою</button>
<button onclick="Territory_Manager.mess.open('${type}',${id}, ${i})">Призначити вісника</button>
</div>
</div>
`;
}
console.log(element);
}
}
},
map: (type, data) => {
map_territory = {};
let center = { lat: 49.5629016, lng: 25.6145625 };
let zoom = 19;
let mytile = L.tileLayer('https://tm.rozenrod.com/webp/{z}/{x}/{y}.webp', {
maxZoom: 20,
minZoom: 15,
tms: true
});
map_territory = L.map('map_territory_manager', {
renderer: L.canvas(),
center,
zoom,
zoomControl: false,
layers: [
mytile
],
});
map_territory.pm.setLang("ua");
if (type == "homestead") {
if (data.geo.lat) map_territory.setView([data.geo.lat, data.geo.lng], 15);
else map_territory.setView([data.points[0][0][0].lat, data.points[0][0][0].lng], 15);
L.polygon(data.points, {
color: colorGroup(data.group_id),
radius: 500,
fillOpacity: 0.3,
dashArray: '20, 15',
dashOffset: '20',
}).on('click', function (e) {
}).addTo(map_territory);
} else if (type == "house") {
map_territory.setView([data.geo.lat, data.geo.lng], 17);
L.polygon(data.points, {
color: "#585858",
fillColor: colorGroup(data.group_id),
fillOpacity: 0.8,
tm_id: `house_${i}`
}).on('click', function (e) {
}).addTo(map_territory);
}
},
mess: {
open: (type, id, number) => {
const block = document.getElementById('territory-new');
const new_worker_button = document.getElementById('new-worker-button');
block.style.display = "";
setTimeout(() => {
block.style.opacity = "1";
}, 100)
new_worker_button.setAttribute("onclick", `Territory_Manager.newWorker('${type}', ${id}, ${number})`);
},
close: () => {
const block = document.getElementById('territory-new');
block.style.opacity = "0";
setTimeout(() => {
block.style.display = "none";
}, 200)
}
},
newWorker: async (type, id, number, name) => {
const uuid = localStorage.getItem('uuid');
const new_worker_button = document.getElementById('new-worker-button');
const group_worker_button = document.getElementById('group-working-button');
let URL, territory_id, data;
const pos = Sheeps.sheeps_list.list.map(e => e.name).indexOf(name ?? document.getElementById("new-worker-name").value);
let sheep = Sheeps.sheeps_list.list[pos];
if (type == "house") {
territory_id = Territory_Manager.entrances.list[number].id;
data = {
name: name ?? document.getElementById("new-worker-name").value,
group_id: Territory_Manager.info.list.group_id,
sheep_id: sheep ? sheep.id : null
}
URL = `${CONFIG.api}history/entrance/${territory_id}`;
}
else if (type == "homestead") {
territory_id = Territory_Manager.info.list.id;
data = {
name: name ?? document.getElementById("new-worker-name").value,
group_id: Territory_Manager.info.list.group_id,
sheep_id: sheep ? sheep.id : null
}
URL = `${CONFIG.api}history/homestead/${territory_id}`;
}
console.log(territory_id, data);
await fetch(URL, {
method: 'POST',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
},
body: JSON.stringify(data)
})
.then(response => {
if (response.status == 200) {
Territory_Manager.mess.close();
Territory_Manager.entrances.list = [];
Territory_Manager.entrances.setHTML(type, id);
return response.json()
} else {
console.log('err');
new_worker_button.innerText = "Помилка";
group_worker_button.innerText = "Помилка";
return
}
})
},
endWorker: async (type, id, territory_id) => {
const end_working_button = document.getElementById('end-working-button');
let uuid = localStorage.getItem('uuid');
let URL = "";
if (type == "house") {
URL = `${CONFIG.api}history/entrance/${territory_id}`;
}
else if (type == "homestead") {
URL = `${CONFIG.api}history/homestead/${territory_id}`;
}
await fetch(URL, {
method: 'PUT',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
},
data: JSON.stringify({})
})
.then(response => {
if (response.status == 200) {
Territory_Manager.entrances.list = [];
Territory_Manager.entrances.setHTML(type, id);
return response.json()
} else {
console.log('err');
end_working_button.innerText = "Помилка";
return
}
})
},
share: async (type, number) => {
let territory, id;
if (type == "house") {
territory = Territory_Manager.entrances.list[number];
id = Territory_Manager.entrances.list[number].id;
}
else if (type == "homestead") {
territory = Territory_Manager.info.list;
id = Territory_Manager.info.list.id;
}
let description = () => {
if (Territory_Manager.info.list.description && Territory_Manager.info.list.description.length > 0) {
return `\n\nДодатково:\n${Territory_Manager.info.list.description}`;
} else {
return '';
}
}
let sheepUuid = () => {
const pos = Sheeps.sheeps_list.list.map(e => e.name).indexOf(territory.history.name);
let sheep = Sheeps.sheeps_list.list[pos];
if (sheep) {
return `\n\nПосилання на Sheep-Service:\n• https://sheep-service.com/?uuid=${sheep.uuid}`;
} else {
return '';
}
}
if (navigator.share) {
console.log("Congrats! Your browser supports Web Share API")
try {
let url;
if(type == 'house') url = `https://sheep-service.com/cards/house/T${Territory_Manager.info.list.id}.webp`;
if(type == 'homestead') url = `https://sheep-service.com/cards/homestead/H${Territory_Manager.info.list.id}.webp`;
const response = await fetch(url);
const blob = await response.blob();
const file = new File([blob], `${type == "house" ? "E" + id : "H" + id}.webp`, { type: blob.type });
await navigator.share({
text: `Територія:\n${type == "house" ? "E" + id : "H" + id}\n\nНаселений пункт:\n${Territory_Manager.info.list.settlement}\n\nВулиця:\n${Territory_Manager.info.list.title + " " + Territory_Manager.info.list.number}${description()}\n\nПризначення:\nЗ ${formattedDate(territory.history.date.start)}\n • До ${formattedDate(territory.history.date.end) ?? formattedDate(territory.history.date.start + (1000 * 2629743 * 4))}${sheepUuid()}`,
files: [file]
});
console.log('Успешно отправлено!');
} catch (error) {
console.error('Ошибка при отправке:', error);
}
} else {
console.log("Sorry! Your browser does not support Web Share API")
}
},
getScreen: async () => {
const center = map_territory.getCenter();
console.log(center.lat, center.lng);
let lat = center.lat;
let lng = center.lng;
let wayId = Territory_Manager.info.list.osm_id;
let zoom = map_territory.getZoom() + 2 ?? 17;
let address = Territory_Manager.info.list.title;
let number = Territory_Manager.info.list.number;
let id = Territory_Manager.info.list.id;
let url = `https://sheep-service.com/api/generator/cards?lat=${lat}&lng=${lng}&type=${type_territory}&wayId=${wayId}&zoom=${zoom}&address=${address}&number=${number}&id=${id}`;
let uuid = localStorage.getItem("uuid");
let result = await fetch(url, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
}).then((response) => response.json());
urlImage = `https://sheep-service.com/cards/${type}/${type == "house" ? "T" : "H"}${id}.webp`;
if(result) {
document.getElementById('menu-picture-error').style.display = 'none';
document.getElementById('menu-picture-ok').style.display = '';
document.getElementById('menu-picture-ok').setAttribute("href", urlImage);
} else {
document.getElementById('menu-picture-error').style.display = '';
document.getElementById('menu-picture-ok').style.display = 'none';
}
}
}

View File

@@ -0,0 +1,418 @@
.page-territory_manager {
width: calc(100% - 18px);
display: flex;
flex-direction: row;
margin: 20px 9px 0 9px;
justify-content: space-between;
position: relative;
}
#territory-info,
#territory-entrance {
width: 100%;
min-height: calc(100vh - 40px - 50px);
height: fit-content;
margin: 0 10px 15px;
border-radius: 15px;
display: flex;
flex-direction: column;
overflow: hidden;
background: var(--ColorThemes1);
color: var(--ColorThemes3);
border: 1px solid var(--ColorThemes2);
box-shadow: var(--shadow-l1);
transition: all .2sease 0s;
}
#territory-info {
position: sticky;
overflow: auto;
top: 20px;
}
#territory-info>.territory-info-image {
width: calc(100% - 20px);
min-height: 200px;
margin: 10px;
border-radius: 10px;
background: var(--ColorThemes0);
position: relative;
display: flex;
overflow: hidden;
background-position: 50%;
background-size: cover;
justify-content: center;
aspect-ratio: 1147 / 751;
max-height: 300px;
}
#territory-info>.territory-info-image>img {
width: 100%;
object-fit: cover;
z-index: 3;
cursor: pointer;
}
#territory-info>.territory-info-image>#map_territory_manager {
width: 100%;
height: 100%;
}
#territory-info>.territory-info-image>img[data-state="active"] {
object-fit: contain;
}
#territory-info>.territory-info-image>.menu-picture {
position: absolute;
right: 10px;
top: 10px;
z-index: 999;
background: var(--ColorThemes0);
border: 1px solid var(--ColorThemes2);
padding: 5px;
border-radius: 6px;
min-width: 70px;
display: flex;
justify-content: space-between;
}
#territory-info>.territory-info-image>.menu-picture>a {
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
#territory-info>.territory-info-image>.menu-picture>a>svg {
width: 22px;
height: 22px;
}
#territory-info>.territory-info-image>.menu-picture>button {
width: 30px;
height: 30px;
border-radius: 2px;
background: var(--PrimaryColor);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
#territory-info>.territory-info-image>.menu-picture>button>svg {
width: 20px;
height: 20px;
fill: var(--PrimaryColorText);
}
#territory-info>.territory-info-text {
width: calc(100% - 40px);
display: flex;
flex-direction: row;
margin: 10px;
border-radius: 10px;
position: relative;
align-items: center;
background: var(--ColorThemes0);
padding: 10px;
}
#territory-info>.territory-info-text>h1 {
font-size: 14px;
font-weight: 400;
color: var(--ColorThemes3);
}
#territory-info>.territory-info-text>h2 {
font-size: 14px;
font-weight: 300;
color: var(--ColorThemes3);
opacity: 0.8;
margin: 0 7px;
}
#territory-info>.territory-info-text>textarea {
width: 100%;
min-height: 100px;
background: var(--ColorThemes0);
color: var(--ColorThemes3);
font-size: 14px;
resize: vertical;
border-radius: 0;
}
#territory-info>#editor_button {
width: calc(100% - 20px);
font-size: 13px;
font-weight: 400;
min-height: 40px;
display: flex;
background: var(--PrimaryColor);
color: var(--PrimaryColorText);
cursor: pointer;
border: 0;
position: relative;
border-radius: 8px;
margin: 20px 10px 10px 10px;
align-items: center;
justify-content: center;
}
#territory-entrance>.entrance {
width: calc(100% - 40px);
color: var(--ColorThemes3);
background-color: var(--ColorThemes2);
border: 1px solid var(--ColorThemes0);
box-shadow: var(--shadow-l1);
display: flex;
flex-direction: column;
align-items: flex-start;
margin: 10px;
padding: 10px;
min-height: 100px;
justify-content: center;
position: relative;
border-radius: 10px;
}
#territory-entrance>.entrance[data-state="working"] {
border: 1px solid var(--PrimaryColor);
}
#territory-entrance>.entrance>#title {
display: flex;
align-items: center;
height: 30px;
margin-bottom: 10px;
justify-content: space-between;
}
#territory-entrance>.entrance>#title>h1 {
width: 100%;
height: 30px;
background: var(--ColorThemes0);
color: var(--ColorThemes3);
border-radius: 6px;
font-size: 16px;
font-weight: 400;
display: flex;
align-items: center;
justify-content: center;
}
#territory-entrance>.entrance>#title>a {
min-height: 30px;
min-width: 30px;
padding: 0;
margin: 0 0 0 10px;
background: var(--PrimaryColor);
display: flex;
align-items: center;
justify-content: center;
}
#territory-entrance>.entrance>#title>a>svg {
width: 25px;
height: 25px;
fill: var(--PrimaryColorText);
}
#territory-entrance>.entrance>div {
display: flex;
margin-bottom: 10px;
flex-direction: row;
align-items: center;
width: 100%;
}
#territory-entrance>.entrance>div>h1 {
font-size: 14px;
font-weight: 400;
color: var(--ColorThemes3);
}
#territory-entrance>.entrance>div>h2,
#territory-entrance>.entrance>div>a,
#territory-entrance>.entrance>div>p {
font-size: 14px;
font-weight: 300;
color: var(--ColorThemes3);
opacity: 0.8;
margin: 0 7px;
display: flex;
align-items: flex-start;
}
#territory-entrance>.entrance>div>a,
#territory-entrance>.entrance>div>p {
color: var(--ColorThemes0);
background: var(--ColorThemes3);
border-radius: 6px;
padding: 2px 5px;
font-weight: 400;
opacity: 1;
}
.date_old {
background: var(--ColorThemes1) !important;
color: var(--ColorThemes3) !important;
font-size: 18px !important;
padding: 5px 10px !important;
}
#territory-entrance>.entrance>.edit_working,
#territory-entrance>.entrance>.edit {
margin-bottom: 0;
}
#territory-entrance>.entrance>.edit_working>button,
#territory-entrance>.entrance>.edit>button {
width: 100%;
font-size: 13px;
font-weight: 400;
min-height: 40px;
display: flex;
padding: 2px 10px;
background: var(--PrimaryColor);
color: var(--PrimaryColorText);
cursor: pointer;
border: 0;
position: relative;
border-radius: 8px;
align-items: center;
justify-content: center;
}
#territory-entrance>.entrance>.edit_working>button:nth-child(2n),
#territory-entrance>.entrance>.edit>button:nth-child(2n) {
margin-left: 5px;
}
#territory-entrance>.entrance>.edit_working>button:nth-child(2n-1),
#territory-entrance>.entrance>.edit>button:nth-child(2n-1) {
margin-right: 5px;
}
#territory-entrance>.entrance>button>span {
display: none;
}
#territory-entrance>.entrance>button>svg {
width: 20px;
height: 20px;
fill: var(--PrimaryColorText);
}
#territory-entrance>.entrance>.apartment_button {
width: 100%;
font-size: 13px;
font-weight: 400;
min-height: 40px;
display: flex;
background: var(--PrimaryColor);
color: var(--PrimaryColorText);
cursor: pointer;
border: 0;
position: relative;
border-radius: 8px;
margin: 20px 0 2px 0;
align-items: center;
justify-content: center;
}
#territory-new {
display: flex;
width: 100%;
height: 100%;
left: 0;
top: 0;
position: fixed;
z-index: 999;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
background: rgb(31 31 33 / 41%);
transition: all .2s ease 0s;
}
#territory-new>.mess {
display: flex;
width: 300px;
height: 200px;
border: 1px solid var(--ColorThemes2);
background: var(--ColorThemes0);
box-shadow: 0px 2px 3px rgb(0 0 0 / 5%), 0px 5px 15px rgb(0 0 0 / 5%), 0px 4px 8px rgb(0 0 0 / 5%), 0px 0px 1px rgb(0 0 0 / 5%);
position: absolute;
top: 50%;
left: 50%;
margin-top: -110px;
margin-left: -160px;
flex-direction: column;
align-items: center;
z-index: 9999;
padding: 10px;
border-radius: 15px;
justify-content: space-between;
}
#territory-new>.mess>span {
color: var(--ColorThemes3);
font-size: 18px;
text-align: center;
}
#territory-new>.mess>select {
width: 100%;
min-width: 140px;
padding: 0 5px;
border-radius: 6px;
height: 30px;
background-color: var(--ColorThemes2);
color: var(--ColorThemes3);
}
#territory-new>.mess>div {
width: 100%;
display: flex;
justify-content: space-between;
flex-direction: row;
}
#territory-new>.mess>div>button {
text-decoration: none;
font-size: 15px;
font-weight: 400;
height: 35px;
color: var(--ColorThemes0);
padding: 2px 10px;
background: var(--ColorThemes3);
cursor: pointer;
border: 0;
margin-bottom: 5px;
margin-left: 0;
width: calc(50% - 5px);
border-radius: 10px;
}
@media (max-width: 1000px),
(max-height: 540px) {
.page-territory_manager {
flex-direction: column;
justify-content: flex-start;
}
#territory-info,
#territory-entrance {
width: calc(100% - 20px);
height: fit-content;
min-height: 100px;
}
#territory-info {
position: relative;
top: auto;
}
}

142
web/lib/router/router.js Normal file
View File

@@ -0,0 +1,142 @@
const Router = {
routes: [],
mode: null,
root: '/',
config: function(options) {
this.mode = options && options.mode && options.mode == 'history' && !!(history.pushState) ? 'history' : 'hash';
this.root = options && options.root ? '/' + this.clearSlashes(options.root) + '/' : '/';
return this;
},
getFragment: function() {
let fragment = '';
if(this.mode === 'history') {
// fragment = this.clearSlashes(decodeURI(location.pathname + location.search));
fragment = this.clearSlashes(decodeURI(window.location.href.replace('/#', '').replace(window.location.origin, '/')));
fragment = fragment.replace(/\?(.*)$/, '');
fragment = this.root != '/' ? fragment.replace(this.root, '') : fragment;
} else {
let match = window.location.href.match(/#(.*)$/);
fragment = match ? match[1] : '';
}
return this.clearSlashes(fragment);
},
getParams: function () {
let query = '';
if(this.mode === 'history') {
query = decodeURI(window.location.href.replace('/#', '')).split("?")[1];
} else {
let index = window.location.hash.indexOf("?");
query = (index !== -1) ? window.location.hash.substring(index) : "";
}
let _query = {};
if (typeof query !== "string") {
return _query;
}
if (query[0] === "?") {
query = query.substring(1);
}
query.split("&").forEach(function (row) {
let parts = row.split("=");
if (parts[0] !== "") {
if (parts[1] === undefined) {
parts[1] = true;
}
_query[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
}
});
return _query;
},
clearSlashes: function(path) {
return path.toString().replace(/\/$/, '').replace(/^\//, '');
},
add: function(re, handler, options) {
if(typeof re == 'function') {
handler = re;
re = '';
}
this.routes.push({ re: re, handler: handler, options: options});
return this;
},
remove: function(param) {
for(let i=0, r; i < this.routes.length, r = this.routes[i]; i++) {
if(r.handler === param || r.re.toString() === param.toString()) {
this.routes.splice(i, 1);
return this;
}
}
return this;
},
flush: function() {
this.routes = [];
this.mode = null;
this.root = '/';
return this;
},
check: function(f) {
let fragment = f || this.getFragment();
for(let i=0; i < this.routes.length; i++) {
let match = fragment.match(this.routes[i].re);
if(fragment == '' || fragment == '/') match = 'home'.match(this.routes[i].re);
if(match) {
match.shift();
let query = this.getParams();
this.routes[i].handler.apply({query}, match);
return this;
}
}
return this;
},
listen: function() {
let self = this;
let current = self.getFragment();
let current_query = self.getParams();
let fn = function() {
if(current !== self.getFragment()) {
current = self.getFragment();
self.check(current);
}
// if(current !== self.getFragment() || JSON.stringify(current_query) !== JSON.stringify(self.getParams())) {
// current = self.getFragment();
// current_query = self.getParams();
// self.check(current);
// }
}
clearInterval(this.interval);
this.interval = setInterval(fn, 50);
return this;
},
navigate: function(path, mode = true) {
path = path || '';
if(mode){
if(this.mode === 'history') {
history.replaceState({position: window.pageYOffset}, null);
history.pushState({position: 0}, null, this.root + this.clearSlashes(path));
} else {
window.location.href = window.location.href.replace(/#(.*)$/, '') + '#' + path;
}
}
return this;
},
update: function(key, value) {
let url = window.location;
let URLParams = new URLSearchParams(url.search);
let RouterParams = Router.getParams();
URLParams.set(key, value);
history.replaceState({position: window.pageYOffset}, null, window.location.origin + window.location.pathname + '?' + URLParams.toString());
}
}
window.addEventListener('click', function (event) {
if (!event.target.matches('[data-route]')) return;
event.preventDefault();
Router.navigate((event.target.href).replace(window.location.origin, ''));
}, false);
if(Router.mode === 'history'){
window.addEventListener('popstate', function (event) {
if (!history.state.url) return;
Router.navigate(history.state.url);
}, false);
}

78
web/lib/router/routes.js Normal file
View File

@@ -0,0 +1,78 @@
Router
.add('territory/manager/(.*)/(.*)', function (type, id) {
Territory_Manager.init(type, id);
pageActive()
routerScroll()
})
.add('territory/editor/(.*)/(.*)', function (type, id) {
Editor.init(type, id);
pageActive()
routerScroll()
})
.add('territory/card/(.*)/(.*)', function (type, id) {
Card.init(type, id);
pageActive()
routerScroll()
})
.add('territory', function () {
Territory.init();
pageActive('territory')
routerScroll()
})
.add('sheeps/(.*)', function (name) {
Sheeps.init(name);
routerScroll();
pageActive('sheeps')
})
.add('sheeps', function () {
Sheeps.init();
routerScroll();
pageActive('sheeps')
})
.add('home', function () {
Home.init();
pageActive('home')
routerScroll()
})
.add('schedule', function () {
Options.init();
routerScroll();
pageActive('schedule')
})
.add('stand', function () {
Stand.init();
routerScroll();
pageActive('stand')
})
.add('options', function () {
Options.init();
routerScroll();
pageActive('options')
})
.add('constructor', function () {
Constructor.init();
routerScroll();
pageActive()
})
.add(function () {
page_404();
routerScroll();
pageActive();
})
function routerScroll() {
if (!history.state) return;
window.scroll(0, history.state.position);
}
function pageActive(element) {
let nav = document.getElementsByTagName("nav")[0];
let dots = nav.getElementsByTagName("li");
for (i = 0; i < dots.length; i++) {
dots[i].children[0].setAttribute('data-state', '');
}
if (element) document.getElementById(`nav-${element}`).setAttribute('data-state', 'active')
}