Додані повідомлення та перепрацьована структура застосунку та api

This commit is contained in:
2026-03-15 00:25:10 +02:00
parent 85483b85bb
commit 4bc9c11512
101 changed files with 5763 additions and 2546 deletions

View File

@@ -1,5 +1,5 @@
const appTerritoryCardStyles = new CSSStyleSheet();
appTerritoryCardStyles.replaceSync(`
// Заміна вмісту таблиці стилів на надані CSS-правила.
const CARD_STYLES_CSS = `
:host {
display: inline-block;
box-sizing: border-box;
@@ -54,14 +54,15 @@ appTerritoryCardStyles.replaceSync(`
width: 100%;
height: 100%;
object-fit: cover;
position: relative;
z-index: 1;
filter: blur(3px);
border-radius: calc(var(--border-radius, 15px) - 5px);
}
.contents {
position: absolute;
top: 0;
left: 0;
z-index: 1;
filter: blur(3px);
}
.contents {
position: relative;
z-index: 2;
background: rgb(64 64 64 / 0.7);
width: 100%;
@@ -89,7 +90,7 @@ appTerritoryCardStyles.replaceSync(`
/* Стили для режима 'sheep' */
/* Стилі для режиму 'sheep' */
.sheep {
margin: 10px;
max-height: 50px;
@@ -116,7 +117,7 @@ appTerritoryCardStyles.replaceSync(`
}
/* Стили для режима 'info' (прогресс) */
/* Стилі для режиму 'info' (прогресс) */
.info {
margin: 10px;
}
@@ -133,7 +134,7 @@ appTerritoryCardStyles.replaceSync(`
}
.info span {
z-index: 2;
font-size: var(--FontSize1, 12px);
font-size: var(--FontSize3, 14px);
color: var(--ColorThemes3, #f3f3f3);
}
.info p {
@@ -158,24 +159,45 @@ appTerritoryCardStyles.replaceSync(`
width: 100%;
height: 100%;
z-index: 10;
border-radius: calc(var(--border-radius, 15px) - 5px);
}
`);
`;
// Створення об'єкта CSSStyleSheet (якщо підтримується)
let appTerritoryCardStyles = null;
if (typeof CSSStyleSheet !== 'undefined' && CSSStyleSheet.prototype.replaceSync) {
appTerritoryCardStyles = new CSSStyleSheet(); // (2) Визначення об'єкта тут
appTerritoryCardStyles.replaceSync(CARD_STYLES_CSS);
}
/**
* Веб-компонент AppTerritoryCard.
* Відображає картку території з фоновим зображенням та різними режимами відображення.
*/
class AppTerritoryCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
// Додаємо стилі в конструкторі, якщо це adoptable
if (this.shadowRoot.adoptedStyleSheets) {
this.shadowRoot.adoptedStyleSheets = [appTerritoryCardStyles];
} else {
// FALLBACK для старих браузерів (наприклад, iOS < 16.4)
const style = document.createElement('style');
style.textContent = CARD_STYLES_CSS;
this.shadowRoot.appendChild(style);
}
}
// Определяем, какие атрибуты будем отслеживать
// Вказуємо, які атрибути ми хочемо відстежувати
static get observedAttributes() {
return ['image', 'address', 'sheep', 'link', 'atWork', 'quantity'];
return ['image', 'address', 'sheep', 'link', 'atWork', 'quantity', 'overdue'];
}
// Геттери та Сеттери для атрибутів
// Вони спрощують роботу з атрибутами як з властивостями DOM-елемента
get image() {
return this.getAttribute('image');
}
@@ -198,6 +220,11 @@ class AppTerritoryCard extends HTMLElement {
}
}
/** * Атрибут 'sheep' може приймати три стани:
* 1. null / відсутній: відключення блоку sheep та info
* 2. порожній рядок ('') / присутній без значення: Режим "Територія не опрацьовується"
* 3. рядок зі значенням: Режим "Територію опрацьовує: [значення]"
*/
get sheep() {
return this.getAttribute('sheep');
}
@@ -228,6 +255,7 @@ class AppTerritoryCard extends HTMLElement {
if (newValue === null) {
this.removeAttribute('atWork');
} else {
// Приводимо до рядка, оскільки атрибути завжди є рядками
this.setAttribute('atWork', String(newValue));
}
}
@@ -239,41 +267,74 @@ class AppTerritoryCard extends HTMLElement {
if (newValue === null) {
this.removeAttribute('quantity');
} else {
// Приводимо до рядка
this.setAttribute('quantity', String(newValue));
}
}
// Вызывается при добавлении элемента в DOM
get overdue() {
return this.getAttribute('address');
}
set overdue(newValue) {
if (newValue === null) {
this.removeAttribute('overdue');
} else {
this.setAttribute('overdue', newValue);
}
}
/**
* connectedCallback викликається, коли елемент додається в DOM.
* Тут ми викликаємо початкове рендеринг.
*/
connectedCallback() {
this.render();
}
// Вызывается при изменении одного из отслеживаемых атрибутов
/**
* attributeChangedCallback викликається при зміні одного зі спостережуваних атрибутів.
*/
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue) {
this.render();
this.render(); // Перерендеринг при зміні атрибута
}
}
/**
* Логіка рендерингу (відображення) вмісту компонента.
*/
render() {
const image = this.getAttribute('image') || '';
const address = this.getAttribute('address') || '';
const sheep = this.getAttribute('sheep'); // Может быть null или ""
const sheep = this.getAttribute('sheep');
const link = this.getAttribute('link') || '#';
const atWork = this.getAttribute('atWork'); // Может быть null
const quantity = this.getAttribute('quantity'); // Может быть null
const atWork = this.getAttribute('atWork');
const quantity = this.getAttribute('quantity');
const overdue = this.getAttribute('overdue') == 'true' ? true : false;
this.shadowRoot.innerHTML = ``;
// Додаємо стилі для старих браузерів
if (!this.shadowRoot.adoptedStyleSheets) {
const style = document.createElement('style');
style.textContent = CARD_STYLES_CSS;
this.shadowRoot.appendChild(style);
}
// --- Логика определения контента ---
let contentHTML = '';
// Перевіряємо, чи має бути увімкнений режим прогресу ('info'):
// обидва атрибути 'atWork' та 'quantity' присутні і є коректними числами.
const isProgressMode = atWork !== null && quantity !== null && !isNaN(parseInt(atWork)) && !isNaN(parseInt(quantity));
const hasSheep = sheep !== null && sheep !== '';
if (isProgressMode) {
// Режим прогресса (свободные подъезды)
// Режим прогресу (вільні під'їзди)
const atWorkNum = parseInt(atWork);
const quantityNum = parseInt(quantity);
const free = quantityNum - atWorkNum;
// Обчислення відсотка прогресу. Уникнення ділення на нуль.
const progressPercent = quantityNum > 0 ? (atWorkNum / quantityNum) * 100 : 100;
contentHTML = `
@@ -286,15 +347,15 @@ class AppTerritoryCard extends HTMLElement {
</div>
`;
} else if (sheep !== null && sheep !== '') {
// Режим ответственного
// Режим опрацювання (значення атрибута 'sheep' є ім'ям опрацювача)
contentHTML = `
<div class="sheep">
<div class="sheep" ${overdue ? `style="background: #bb4444;"` : ``}>
<span>Територію опрацьовує:</span>
<p>${sheep}</p>
</div>
`;
} else if (sheep !== null) {
// Режим "не опрацьовується"
} else if (sheep !== null && sheep === '') {
// Режим "не опрацьовується" (атрибут 'sheep' присутній, але порожній)
contentHTML = `
<div class="sheep">
<span>Територія не опрацьовується</span>
@@ -302,9 +363,9 @@ class AppTerritoryCard extends HTMLElement {
`;
}
// --- Сборка всего шаблона ---
this.shadowRoot.innerHTML = `
<div class="card">
// --- Складання всього шаблону ---
this.shadowRoot.innerHTML += `
<div class="card" ${overdue ? `title="Термін опрацювання минув!"` : ``}>
<img src="${image}" alt="${address}" />
<div class="contents">
<h1 class="address">${address}</h1>
@@ -316,8 +377,42 @@ class AppTerritoryCard extends HTMLElement {
}
}
// Регистрируем веб-компонент
// Реєструємо веб-компонент у браузері
customElements.define('app-territory-card', AppTerritoryCard);
// document.getElementById('app-territory-card-1').setAttribute('sheep', 'test')
/*
============================
ПРИКЛАД ВИКОРИСТАННЯ
============================
*/
/*
<app-territory-card
address="Вул. Прикладна, 15А"
image="https://example.com/images/territory-1.jpg"
link="/territory/15a"
atWork="12"
quantity="20"
></app-territory-card>
<app-territory-card
address="Просп. Науковий, 5"
image="https://example.com/images/territory-2.jpg"
link="/territory/naukovyi-5"
sheep="Іван Петренко"
></app-territory-card>
<app-territory-card
address="Майдан Свободи, 1"
image="https://example.com/images/territory-3.jpg"
link="/territory/svobody-1"
sheep=""
></app-territory-card>
<app-territory-card
address="Вул. Безіменна, 99"
image="https://example.com/images/territory-4.jpg"
link="/territory/bezymenna-99"
></app-territory-card>
*/