Додан моніторінг застосунку
Додани веб компоненти карточок територій та повідомлень
This commit is contained in:
326
web/lib/customElements/notification.js
Normal file
326
web/lib/customElements/notification.js
Normal file
@@ -0,0 +1,326 @@
|
||||
class AppNotificationContainer extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
|
||||
// Настройки по умолчанию
|
||||
this._timeout = 4000;
|
||||
this._maxVisible = 5;
|
||||
this._position = 'top-right';
|
||||
this._mobileBottomEnabled = false;
|
||||
|
||||
this._container = document.createElement('div');
|
||||
this._container.className = 'app-notification-container';
|
||||
this.shadowRoot.appendChild(this._container);
|
||||
|
||||
this._insertStyles();
|
||||
|
||||
this._icons = {
|
||||
info: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><path d="M 15 3 C 13.895 3 13 3.895 13 5 L 13 5.2929688 C 10.109011 6.1538292 8 8.8293311 8 12 L 8 14.757812 C 8 17.474812 6.921 20.079 5 22 A 1 1 0 0 0 4 23 A 1 1 0 0 0 5 24 L 25 24 A 1 1 0 0 0 26 23 A 1 1 0 0 0 25 22 C 23.079 20.079 22 17.474812 22 14.757812 L 22 12 C 22 8.8293311 19.890989 6.1538292 17 5.2929688 L 17 5 C 17 3.895 16.105 3 15 3 z M 3.9550781 7.9882812 A 1.0001 1.0001 0 0 0 3.1054688 8.5527344 C 3.1054688 8.5527344 2 10.666667 2 13 C 2 15.333333 3.1054687 17.447266 3.1054688 17.447266 A 1.0001165 1.0001165 0 0 0 4.8945312 16.552734 C 4.8945312 16.552734 4 14.666667 4 13 C 4 11.333333 4.8945313 9.4472656 4.8945312 9.4472656 A 1.0001 1.0001 0 0 0 3.9550781 7.9882812 z M 26.015625 7.9882812 A 1.0001 1.0001 0 0 0 25.105469 9.4472656 C 25.105469 9.4472656 26 11.333333 26 13 C 26 14.666667 25.105469 16.552734 25.105469 16.552734 A 1.0001163 1.0001163 0 1 0 26.894531 17.447266 C 26.894531 17.447266 28 15.333333 28 13 C 28 10.666667 26.894531 8.5527344 26.894531 8.5527344 A 1.0001 1.0001 0 0 0 26.015625 7.9882812 z M 12 26 C 12 27.657 13.343 29 15 29 C 16.657 29 18 27.657 18 26 L 12 26 z"/></svg>`,
|
||||
success: `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8' style="width: 17px;height: 17px;"><path d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/></svg>`,
|
||||
warn: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"> <path d="M 15 3 C 14.168432 3 13.456063 3.5067238 13.154297 4.2285156 L 2.3007812 22.947266 L 2.3007812 22.949219 A 2 2 0 0 0 2 24 A 2 2 0 0 0 4 26 A 2 2 0 0 0 4.140625 25.994141 L 4.1445312 26 L 15 26 L 25.855469 26 L 25.859375 25.992188 A 2 2 0 0 0 26 26 A 2 2 0 0 0 28 24 A 2 2 0 0 0 27.699219 22.947266 L 27.683594 22.919922 A 2 2 0 0 0 27.681641 22.917969 L 16.845703 4.2285156 C 16.543937 3.5067238 15.831568 3 15 3 z M 13.787109 11.359375 L 16.212891 11.359375 L 16.011719 17.832031 L 13.988281 17.832031 L 13.787109 11.359375 z M 15.003906 19.810547 C 15.825906 19.810547 16.318359 20.252813 16.318359 21.007812 C 16.318359 21.748812 15.825906 22.189453 15.003906 22.189453 C 14.175906 22.189453 13.679688 21.748813 13.679688 21.007812 C 13.679688 20.252813 14.174906 19.810547 15.003906 19.810547 z"/></svg>`,
|
||||
error: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><path d="M 10.03125 2.9042969 A 1.0001 1.0001 0 0 0 9.0605469 4.2578125 C 9.0605469 4.2578125 9.7494688 5.9996671 11.488281 7.0800781 C 11.080693 7.2039808 10.414387 7.5446908 9.8027344 8.4570312 C 9.4322834 8.3403526 9.1037156 8.2185154 8.8496094 8.0976562 C 8.3997876 7.8837103 8.118603 7.6807271 7.9589844 7.546875 C 7.7993657 7.4130229 7.8046875 7.40625 7.8046875 7.40625 A 1.0001 1.0001 0 0 0 7 7 L 5 7 A 1.0001 1.0001 0 1 0 5 9 L 6.5957031 9 C 6.6368531 9.038228 6.6271651 9.038995 6.6738281 9.078125 C 6.961397 9.3192729 7.3888062 9.6162897 7.9902344 9.9023438 C 9.1930908 10.474451 11.083447 11 13.935547 11 A 1.0001 1.0001 0 0 0 14.140625 10.980469 C 14.430223 10.987386 14.697172 11 15.017578 11 C 15.326932 11 15.582943 10.988887 15.863281 10.982422 A 1.0001 1.0001 0 0 0 16.064453 11 C 18.916553 11 20.806909 10.474451 22.009766 9.9023438 C 22.611194 9.6162897 23.038603 9.3192729 23.326172 9.078125 C 23.372834 9.0389949 23.363147 9.0382279 23.404297 9 L 25 9 A 1.0001 1.0001 0 1 0 25 7 L 23 7 A 1.0001 1.0001 0 0 0 22.195312 7.40625 C 22.195312 7.40625 22.200612 7.41302 22.041016 7.546875 C 21.881397 7.6807271 21.600212 7.8837103 21.150391 8.0976562 C 20.891444 8.2208175 20.55751 8.3444389 20.177734 8.4628906 C 19.558423 7.539139 18.907199 7.1978378 18.517578 7.0761719 C 20.252095 5.9954925 20.939453 4.2578125 20.939453 4.2578125 A 1.0001 1.0001 0 0 0 20.039062 2.9042969 A 1.0001 1.0001 0 0 0 19.060547 3.5761719 C 19.060547 3.5761719 18.556779 5.088719 16.882812 5.6757812 C 16.36708 5.2573881 15.71568 5 15 5 C 14.284868 5 13.632808 5.2576596 13.117188 5.6757812 C 11.443221 5.088719 10.939453 3.5761719 10.939453 3.5761719 A 1.0001 1.0001 0 0 0 10.03125 2.9042969 z M 5.9628906 11 A 1.0001 1.0001 0 0 0 5.6835938 11.050781 L 2.6835938 12.050781 A 1.0005646 1.0005646 0 0 0 3.3164062 13.949219 L 5.9707031 13.064453 C 6.0672386 13.111686 6.3494962 13.235909 6.5917969 13.34375 C 6.2888038 14.107541 6 15.15686 6 16.425781 C 6 17.948961 6.3086267 19.289595 6.7949219 20.453125 L 6.1601562 22.357422 L 3.4453125 24.167969 A 1.0001 1.0001 0 1 0 4.5546875 25.832031 L 7.5546875 23.832031 A 1.0001 1.0001 0 0 0 7.9492188 23.316406 L 8.1367188 22.751953 C 9.8000084 24.902319 11.988204 26 13 26 C 13.742 26 14 25.42 14 25 L 14 16 C 14 15.447 14.448 15 15 15 C 15.552 15 16 15.447 16 16 L 16 25 C 16 25.42 16.258 26 17 26 C 18.011796 26 20.199992 24.902319 21.863281 22.751953 L 22.050781 23.316406 A 1.0001 1.0001 0 0 0 22.445312 23.832031 L 25.445312 25.832031 A 1.0001 1.0001 0 1 0 26.554688 24.167969 L 23.839844 22.357422 L 23.205078 20.453125 C 23.691373 19.289595 24 17.948961 24 16.425781 C 24 15.15686 23.711196 14.107541 23.408203 13.34375 C 23.650504 13.235909 23.932762 13.111686 24.029297 13.064453 L 26.683594 13.949219 A 1.0005646 1.0005646 0 1 0 27.316406 12.050781 L 24.316406 11.050781 A 1.0001 1.0001 0 0 0 24.021484 11 A 1.0001 1.0001 0 0 0 23.552734 11.105469 C 23.552734 11.105469 20.660591 12.508607 17.513672 12.896484 C 16.740098 12.956149 15.915495 13 15 13 C 14.084505 13 13.259902 12.956149 12.486328 12.896484 C 9.3394093 12.508607 6.4472656 11.105469 6.4472656 11.105469 A 1.0001 1.0001 0 0 0 5.9628906 11 z"/></svg>`
|
||||
};
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ['timeout', 'max-visible', 'position', 'mobile-position'];
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this._updateSettings();
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (oldValue !== newValue) {
|
||||
this._updateSettings();
|
||||
}
|
||||
}
|
||||
|
||||
_updateSettings() {
|
||||
this._position = this.getAttribute('position') || 'top-right';
|
||||
this._maxVisible = parseInt(this.getAttribute('max-visible')) || 5;
|
||||
this._timeout = parseInt(this.getAttribute('timeout')) || 4000;
|
||||
|
||||
const mobilePosAttr = this.getAttribute('mobile-position');
|
||||
// Если атрибут установлен в 'bottom' или присутствует (как пустая строка, если это булевый атрибут)
|
||||
this._mobileBottomEnabled = mobilePosAttr === 'bottom' || mobilePosAttr === '';
|
||||
|
||||
this._container.setAttribute('data-position', this._position);
|
||||
|
||||
this._applyMobileStyles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Динамически применяет класс, который активирует мобильные стили "только снизу".
|
||||
*/
|
||||
_applyMobileStyles() {
|
||||
if (this._mobileBottomEnabled) {
|
||||
this._container.classList.add('mobile-bottom');
|
||||
} else {
|
||||
this._container.classList.remove('mobile-bottom');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Публичный метод для изменения настройки мобильной позиции во время выполнения.
|
||||
* @param {boolean} enable - true, чтобы принудительно устанавливать позицию снизу на мобильных, false, чтобы использовать обычные @media стили.
|
||||
*/
|
||||
setMobileBottom(enable) {
|
||||
this._mobileBottomEnabled = !!enable;
|
||||
this._applyMobileStyles();
|
||||
}
|
||||
|
||||
show(message, options = {}) {
|
||||
const {
|
||||
type = 'info',
|
||||
timeout = this._timeout,
|
||||
title,
|
||||
onClick,
|
||||
lock
|
||||
} = options;
|
||||
|
||||
const content = typeof message === 'string'
|
||||
? { title: title || '', text: message }
|
||||
: message;
|
||||
|
||||
while (this._container.children.length >= this._maxVisible) {
|
||||
const first = this._container.firstElementChild;
|
||||
if (first) first.remove();
|
||||
else break;
|
||||
}
|
||||
|
||||
const node = document.createElement('div');
|
||||
node.className = `app-notification ${type}`;
|
||||
if (onClick) node.style.cursor = "pointer"
|
||||
|
||||
const icon = document.createElement('div');
|
||||
icon.className = 'icon';
|
||||
icon.innerHTML = this._icons[type] || this._icons.info;
|
||||
|
||||
const body = document.createElement('div');
|
||||
body.className = 'body';
|
||||
if (content.title) {
|
||||
const t = document.createElement('div');
|
||||
t.className = 'title';
|
||||
t.textContent = content.title;
|
||||
body.appendChild(t);
|
||||
}
|
||||
const txt = document.createElement('div');
|
||||
txt.className = 'text';
|
||||
txt.textContent = content.text || '';
|
||||
body.appendChild(txt);
|
||||
|
||||
node.appendChild(icon);
|
||||
node.appendChild(body);
|
||||
|
||||
if (!onClick && !lock) {
|
||||
const closeDiv = document.createElement('div');
|
||||
closeDiv.className = 'blockClose';
|
||||
node.appendChild(closeDiv);
|
||||
|
||||
const closeBtn = document.createElement('button');
|
||||
closeBtn.className = 'close';
|
||||
closeBtn.setAttribute('aria-label', 'Закрыть уведомление');
|
||||
closeBtn.innerHTML = '<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>';
|
||||
closeDiv.appendChild(closeBtn);
|
||||
closeBtn.addEventListener('click', () => this._removeNode(node));
|
||||
}
|
||||
|
||||
this._container.appendChild(node);
|
||||
requestAnimationFrame(() => node.classList.add('show'));
|
||||
|
||||
let timer = null;
|
||||
const startTimer = () => {
|
||||
if (timeout === 0) return;
|
||||
timer = setTimeout(() => this._removeNode(node), timeout);
|
||||
};
|
||||
const clearTimer = () => { if (timer) { clearTimeout(timer); timer = null; } };
|
||||
|
||||
node.addEventListener('mouseenter', clearTimer);
|
||||
node.addEventListener('mouseleave', startTimer);
|
||||
|
||||
if (typeof onClick === 'function') {
|
||||
node.addEventListener('click', () => {
|
||||
try { onClick(); } catch (e) { }
|
||||
this._removeNode(node);
|
||||
});
|
||||
}
|
||||
|
||||
startTimer();
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
_removeNode(node) {
|
||||
if (!node || !node.parentElement) return;
|
||||
node.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
if (node && node.parentElement) node.parentElement.removeChild(node);
|
||||
}, 200);
|
||||
}
|
||||
|
||||
clearAll() {
|
||||
if (!this._container) return;
|
||||
Array.from(this._container.children).forEach(n => this._removeNode(n));
|
||||
}
|
||||
|
||||
info(message, opts = {}) { return this.show(message, { ...opts, type: 'info' }); }
|
||||
success(message, opts = {}) { return this.show(message, { ...opts, type: 'success' }); }
|
||||
warn(message, opts = {}) { return this.show(message, { ...opts, type: 'warn' }); }
|
||||
error(message, opts = {}) { return this.show(message, { ...opts, type: 'error' }); }
|
||||
click(message, opts = {}) { return this.show(message, { ...opts, onClick: opts.f }); }
|
||||
|
||||
|
||||
_insertStyles() {
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.app-notification-container {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
pointer-events: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 12px;
|
||||
}
|
||||
.app-notification-container[data-position="top-right"] { top: 8px; right: 8px; align-items: flex-end; }
|
||||
.app-notification-container[data-position="top-left"] { top: 8px; left: 8px; align-items: flex-start; }
|
||||
.app-notification-container[data-position="bottom-right"] { bottom: 8px; right: 8px; align-items: flex-end; }
|
||||
.app-notification-container[data-position="bottom-left"] { bottom: 8px; left: 8px; align-items: flex-start; }
|
||||
|
||||
.app-notification {
|
||||
pointer-events: auto;
|
||||
min-width: 220px;
|
||||
max-width: 360px;
|
||||
background: #111;
|
||||
color: #fff;
|
||||
padding: 10px 12px 10px 12px;
|
||||
border-radius: var(--border-radius, 8px);
|
||||
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
|
||||
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
|
||||
font-size: var(--FontSize2, 14px);
|
||||
line-height: 1.2;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
transform: translateY(-6px) scale(0.995);
|
||||
transition: opacity .18s ease, transform .18s ease;
|
||||
position: relative;
|
||||
}
|
||||
.app-notification.show {
|
||||
opacity: 0.95;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
.app-notification .icon {
|
||||
font-size: 18px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
border-radius: calc(var(--border-radius, 8px) - 5px);
|
||||
padding: 8px;
|
||||
}
|
||||
.app-notification .icon svg{
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: #fff;
|
||||
}
|
||||
.app-notification .body { flex:1; }
|
||||
.app-notification .title { font-weight: 600; margin-bottom: 4px; font-size: 13px; }
|
||||
.app-notification .blockClose {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
.app-notification .blockClose .close {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
margin-left: 8px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
}
|
||||
.app-notification .blockClose .close svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
fill: #fff;
|
||||
opacity: 0.8;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.app-notification.info {
|
||||
background: var(--ColorThemes3, #2196F3);
|
||||
color: var(--ColorThemes0, #ffffff);
|
||||
}
|
||||
.app-notification.info .icon { background: var(--ColorThemes0, #ffffff); }
|
||||
.app-notification.info .icon svg{fill: var(--ColorThemes3, #2196F3);}
|
||||
.app-notification.info .close svg{fill: var(--ColorThemes0, #ffffff);}
|
||||
|
||||
.app-notification.success { background: #52ac56; }
|
||||
.app-notification.success .icon { background: #6dc450; }
|
||||
.app-notification.success .close svg{fill: #fff;}
|
||||
|
||||
.app-notification.warn { background: #d18515; }
|
||||
.app-notification.warn .icon { background: #eaad57; }
|
||||
.app-notification.warn .close svg{fill: #fff;}
|
||||
|
||||
.app-notification.error { background: #9c2424; }
|
||||
.app-notification.error .icon { background: #c45050; }
|
||||
.app-notification.error .close svg{fill: #fff;}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.app-notification-container {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: calc(100% - 24px);
|
||||
align-items: center !important;
|
||||
}
|
||||
.app-notification-container .app-notification {
|
||||
max-width: 95%;
|
||||
min-width: 95%;
|
||||
}
|
||||
|
||||
.app-notification-container.mobile-bottom {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
this.shadowRoot.appendChild(style);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('app-notification-container', AppNotificationContainer);
|
||||
|
||||
/* <app-notification-container
|
||||
id="notif-manager"
|
||||
position="top-right"
|
||||
max-visible="5"
|
||||
timeout="4000"
|
||||
mobile-position>
|
||||
</app-notification-container> */
|
||||
// const Notifier = document.getElementById('notif-manager');
|
||||
|
||||
// 💡 Включить принудительную позицию снизу для мобильных
|
||||
// Notifier.setMobileBottom(true);
|
||||
|
||||
// 💡 Отключить принудительную позицию снизу (вернется к поведению @media или position)
|
||||
// Notifier.setMobileBottom(false);
|
||||
|
||||
|
||||
// Пример использования
|
||||
|
||||
// Notifier.info('Настройки мобильной позиции изменены.');
|
||||
// Notifier.info('Привет! Это ваше первое уведомление через Web Component.', {
|
||||
// title: 'Успешная инициализация',
|
||||
// onClick: () => alert('Вы кликнули!'),
|
||||
// lock: false
|
||||
// });
|
||||
// Notifier.success('Успешная операция.');
|
||||
// Notifier.error('Критическая ошибка!', { timeout: 0, lock: true });
|
||||
// Notifier.warn({ title: `Metrics`, text: `З'єднання встановлено` }, { timeout: 0 });
|
||||
Reference in New Issue
Block a user