Add loading indicator for main items in admin view to enhance user experience
This commit is contained in:
@@ -730,8 +730,43 @@
|
|||||||
let mainItemsLoadingMore = false;
|
let mainItemsLoadingMore = false;
|
||||||
let mainItemsObserver = null;
|
let mainItemsObserver = null;
|
||||||
let mainItemsSentinel = null;
|
let mainItemsSentinel = null;
|
||||||
|
let mainItemsLoadingIndicator = null;
|
||||||
let mainItemsScrollPrefetchBound = false;
|
let mainItemsScrollPrefetchBound = false;
|
||||||
|
|
||||||
|
function ensureMainItemsLoadingIndicator() {
|
||||||
|
const itemsContainer = document.querySelector('#items-container');
|
||||||
|
if (!itemsContainer) return null;
|
||||||
|
|
||||||
|
if (!mainItemsLoadingIndicator) {
|
||||||
|
mainItemsLoadingIndicator = document.createElement('div');
|
||||||
|
mainItemsLoadingIndicator.id = 'main-items-loading-indicator';
|
||||||
|
mainItemsLoadingIndicator.className = 'items-loading-indicator';
|
||||||
|
mainItemsLoadingIndicator.innerHTML = `
|
||||||
|
<div class="loading-track"><div class="loading-fill"></div></div>
|
||||||
|
<div class="loading-label">Weitere Objekte werden vorbereitet...</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemsContainer.appendChild(mainItemsLoadingIndicator);
|
||||||
|
return itemsContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMainItemsLoadingIndicator() {
|
||||||
|
const itemsContainer = ensureMainItemsLoadingIndicator();
|
||||||
|
if (!itemsContainer || !mainItemsLoadingIndicator) return;
|
||||||
|
|
||||||
|
const shouldShow = mainItemsHasMore || mainItemsLoadingMore;
|
||||||
|
mainItemsLoadingIndicator.style.display = shouldShow ? 'flex' : 'none';
|
||||||
|
mainItemsLoadingIndicator.classList.toggle('is-loading', mainItemsLoadingMore);
|
||||||
|
|
||||||
|
const label = mainItemsLoadingIndicator.querySelector('.loading-label');
|
||||||
|
if (label) {
|
||||||
|
label.textContent = mainItemsLoadingMore
|
||||||
|
? 'Weitere Objekte werden geladen...'
|
||||||
|
: 'Weitere Objekte werden vorbereitet...';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function maybePrefetchMainItems() {
|
function maybePrefetchMainItems() {
|
||||||
const itemsContainer = document.querySelector('#items-container');
|
const itemsContainer = document.querySelector('#items-container');
|
||||||
if (!itemsContainer || !mainItemsHasMore || mainItemsLoadingMore) {
|
if (!itemsContainer || !mainItemsHasMore || mainItemsLoadingMore) {
|
||||||
@@ -745,8 +780,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainItemsLoadingMore = true;
|
mainItemsLoadingMore = true;
|
||||||
|
updateMainItemsLoadingIndicator();
|
||||||
loadItems(mainItemsNextOffset, true).finally(() => {
|
loadItems(mainItemsNextOffset, true).finally(() => {
|
||||||
mainItemsLoadingMore = false;
|
mainItemsLoadingMore = false;
|
||||||
|
updateMainItemsLoadingIndicator();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1054,11 +1091,15 @@
|
|||||||
|
|
||||||
mainItemsNextOffset = (data.offset || offset) + (data.count || pageItems.length);
|
mainItemsNextOffset = (data.offset || offset) + (data.count || pageItems.length);
|
||||||
mainItemsHasMore = Boolean(data.has_more);
|
mainItemsHasMore = Boolean(data.has_more);
|
||||||
|
updateMainItemsLoadingIndicator();
|
||||||
setupMainItemsLazyLoading();
|
setupMainItemsLazyLoading();
|
||||||
maybePrefetchMainItems();
|
maybePrefetchMainItems();
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error fetching items:', error);
|
console.error('Error fetching items:', error);
|
||||||
|
mainItemsLoadingMore = false;
|
||||||
|
mainItemsHasMore = false;
|
||||||
|
updateMainItemsLoadingIndicator();
|
||||||
if (append) {
|
if (append) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1072,6 +1113,8 @@
|
|||||||
const itemsContainer = document.querySelector('#items-container');
|
const itemsContainer = document.querySelector('#items-container');
|
||||||
if (!itemsContainer) return null;
|
if (!itemsContainer) return null;
|
||||||
|
|
||||||
|
ensureMainItemsLoadingIndicator();
|
||||||
|
|
||||||
if (!mainItemsSentinel) {
|
if (!mainItemsSentinel) {
|
||||||
mainItemsSentinel = document.createElement('div');
|
mainItemsSentinel = document.createElement('div');
|
||||||
mainItemsSentinel.id = 'main-items-sentinel';
|
mainItemsSentinel.id = 'main-items-sentinel';
|
||||||
@@ -1117,8 +1160,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainItemsLoadingMore = true;
|
mainItemsLoadingMore = true;
|
||||||
|
updateMainItemsLoadingIndicator();
|
||||||
loadItems(mainItemsNextOffset, true).finally(() => {
|
loadItems(mainItemsNextOffset, true).finally(() => {
|
||||||
mainItemsLoadingMore = false;
|
mainItemsLoadingMore = false;
|
||||||
|
updateMainItemsLoadingIndicator();
|
||||||
});
|
});
|
||||||
}, {
|
}, {
|
||||||
root: itemsContainer,
|
root: itemsContainer,
|
||||||
@@ -1127,6 +1172,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
mainItemsObserver.observe(mainItemsSentinel);
|
mainItemsObserver.observe(mainItemsSentinel);
|
||||||
|
updateMainItemsLoadingIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchByCode() {
|
function searchByCode() {
|
||||||
@@ -2846,6 +2892,57 @@
|
|||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.items-loading-indicator {
|
||||||
|
display: none;
|
||||||
|
flex: 0 0 220px;
|
||||||
|
min-width: 220px;
|
||||||
|
max-width: 220px;
|
||||||
|
height: 180px;
|
||||||
|
align-self: center;
|
||||||
|
margin-right: 8px;
|
||||||
|
border: 1px solid #dbe3ee;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #f8fafc;
|
||||||
|
color: #334155;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
scroll-snap-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-loading-indicator .loading-label {
|
||||||
|
font-size: 0.84rem;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.3;
|
||||||
|
max-width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-loading-indicator .loading-track {
|
||||||
|
width: 160px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #e2e8f0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-loading-indicator .loading-fill {
|
||||||
|
width: 45%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: linear-gradient(90deg, #60a5fa, #2563eb);
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-loading-indicator.is-loading .loading-fill {
|
||||||
|
animation: items-loader-slide 1.05s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes items-loader-slide {
|
||||||
|
0% { transform: translateX(-100%); }
|
||||||
|
100% { transform: translateX(260%); }
|
||||||
|
}
|
||||||
|
|
||||||
.item-card {
|
.item-card {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
|
|||||||
@@ -323,6 +323,57 @@
|
|||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.items-loading-indicator {
|
||||||
|
display: none;
|
||||||
|
flex: 0 0 220px;
|
||||||
|
min-width: 220px;
|
||||||
|
max-width: 220px;
|
||||||
|
height: 180px;
|
||||||
|
align-self: center;
|
||||||
|
margin-right: 8px;
|
||||||
|
border: 1px solid #dbe3ee;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #f8fafc;
|
||||||
|
color: #334155;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
scroll-snap-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-loading-indicator .loading-label {
|
||||||
|
font-size: 0.84rem;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.3;
|
||||||
|
max-width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-loading-indicator .loading-track {
|
||||||
|
width: 160px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #e2e8f0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-loading-indicator .loading-fill {
|
||||||
|
width: 45%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: linear-gradient(90deg, #60a5fa, #2563eb);
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.items-loading-indicator.is-loading .loading-fill {
|
||||||
|
animation: items-loader-slide 1.05s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes items-loader-slide {
|
||||||
|
0% { transform: translateX(-100%); }
|
||||||
|
100% { transform: translateX(260%); }
|
||||||
|
}
|
||||||
|
|
||||||
.item-card {
|
.item-card {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
@@ -3261,9 +3312,44 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
let mainAdminItemsLoadingMore = false;
|
let mainAdminItemsLoadingMore = false;
|
||||||
let mainAdminItemsObserver = null;
|
let mainAdminItemsObserver = null;
|
||||||
let mainAdminItemsSentinel = null;
|
let mainAdminItemsSentinel = null;
|
||||||
|
let mainAdminItemsLoadingIndicator = null;
|
||||||
let mainAdminItemsScrollPrefetchBound = false;
|
let mainAdminItemsScrollPrefetchBound = false;
|
||||||
let totalItemsInSystem = 0;
|
let totalItemsInSystem = 0;
|
||||||
|
|
||||||
|
function ensureMainAdminItemsLoadingIndicator() {
|
||||||
|
const itemsContainer = document.querySelector('#items-container');
|
||||||
|
if (!itemsContainer) return null;
|
||||||
|
|
||||||
|
if (!mainAdminItemsLoadingIndicator) {
|
||||||
|
mainAdminItemsLoadingIndicator = document.createElement('div');
|
||||||
|
mainAdminItemsLoadingIndicator.id = 'main-admin-items-loading-indicator';
|
||||||
|
mainAdminItemsLoadingIndicator.className = 'items-loading-indicator';
|
||||||
|
mainAdminItemsLoadingIndicator.innerHTML = `
|
||||||
|
<div class="loading-track"><div class="loading-fill"></div></div>
|
||||||
|
<div class="loading-label">Weitere Objekte werden vorbereitet...</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemsContainer.appendChild(mainAdminItemsLoadingIndicator);
|
||||||
|
return itemsContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMainAdminItemsLoadingIndicator() {
|
||||||
|
const itemsContainer = ensureMainAdminItemsLoadingIndicator();
|
||||||
|
if (!itemsContainer || !mainAdminItemsLoadingIndicator) return;
|
||||||
|
|
||||||
|
const shouldShow = mainAdminItemsHasMore || mainAdminItemsLoadingMore;
|
||||||
|
mainAdminItemsLoadingIndicator.style.display = shouldShow ? 'flex' : 'none';
|
||||||
|
mainAdminItemsLoadingIndicator.classList.toggle('is-loading', mainAdminItemsLoadingMore);
|
||||||
|
|
||||||
|
const label = mainAdminItemsLoadingIndicator.querySelector('.loading-label');
|
||||||
|
if (label) {
|
||||||
|
label.textContent = mainAdminItemsLoadingMore
|
||||||
|
? 'Weitere Objekte werden geladen...'
|
||||||
|
: 'Weitere Objekte werden vorbereitet...';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function maybePrefetchMainAdminItems() {
|
function maybePrefetchMainAdminItems() {
|
||||||
const itemsContainer = document.querySelector('#items-container');
|
const itemsContainer = document.querySelector('#items-container');
|
||||||
if (!itemsContainer || !mainAdminItemsHasMore || mainAdminItemsLoadingMore) {
|
if (!itemsContainer || !mainAdminItemsHasMore || mainAdminItemsLoadingMore) {
|
||||||
@@ -3277,8 +3363,10 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainAdminItemsLoadingMore = true;
|
mainAdminItemsLoadingMore = true;
|
||||||
|
updateMainAdminItemsLoadingIndicator();
|
||||||
loadItems(mainAdminItemsNextOffset, true).finally(() => {
|
loadItems(mainAdminItemsNextOffset, true).finally(() => {
|
||||||
mainAdminItemsLoadingMore = false;
|
mainAdminItemsLoadingMore = false;
|
||||||
|
updateMainAdminItemsLoadingIndicator();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3582,11 +3670,15 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
|
|
||||||
mainAdminItemsNextOffset = (data.offset || offset) + (data.count || pageItems.length);
|
mainAdminItemsNextOffset = (data.offset || offset) + (data.count || pageItems.length);
|
||||||
mainAdminItemsHasMore = Boolean(data.has_more);
|
mainAdminItemsHasMore = Boolean(data.has_more);
|
||||||
|
updateMainAdminItemsLoadingIndicator();
|
||||||
setupMainAdminItemsLazyLoading();
|
setupMainAdminItemsLazyLoading();
|
||||||
maybePrefetchMainAdminItems();
|
maybePrefetchMainAdminItems();
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error fetching items:', error);
|
console.error('Error fetching items:', error);
|
||||||
|
mainAdminItemsLoadingMore = false;
|
||||||
|
mainAdminItemsHasMore = false;
|
||||||
|
updateMainAdminItemsLoadingIndicator();
|
||||||
if (append) {
|
if (append) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3604,6 +3696,8 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
const itemsContainer = document.querySelector('#items-container');
|
const itemsContainer = document.querySelector('#items-container');
|
||||||
if (!itemsContainer) return null;
|
if (!itemsContainer) return null;
|
||||||
|
|
||||||
|
ensureMainAdminItemsLoadingIndicator();
|
||||||
|
|
||||||
if (!mainAdminItemsSentinel) {
|
if (!mainAdminItemsSentinel) {
|
||||||
mainAdminItemsSentinel = document.createElement('div');
|
mainAdminItemsSentinel = document.createElement('div');
|
||||||
mainAdminItemsSentinel.id = 'main-admin-items-sentinel';
|
mainAdminItemsSentinel.id = 'main-admin-items-sentinel';
|
||||||
@@ -3644,8 +3738,10 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainAdminItemsLoadingMore = true;
|
mainAdminItemsLoadingMore = true;
|
||||||
|
updateMainAdminItemsLoadingIndicator();
|
||||||
loadItems(mainAdminItemsNextOffset, true).finally(() => {
|
loadItems(mainAdminItemsNextOffset, true).finally(() => {
|
||||||
mainAdminItemsLoadingMore = false;
|
mainAdminItemsLoadingMore = false;
|
||||||
|
updateMainAdminItemsLoadingIndicator();
|
||||||
});
|
});
|
||||||
}, {
|
}, {
|
||||||
root: itemsContainer,
|
root: itemsContainer,
|
||||||
@@ -3654,6 +3750,7 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
});
|
});
|
||||||
|
|
||||||
mainAdminItemsObserver.observe(mainAdminItemsSentinel);
|
mainAdminItemsObserver.observe(mainAdminItemsSentinel);
|
||||||
|
updateMainAdminItemsLoadingIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchByCode() {
|
function searchByCode() {
|
||||||
|
|||||||
Reference in New Issue
Block a user