From af8f5ba04eddae8cc364e402ead7d61fa3762585 Mon Sep 17 00:00:00 2001 From: Will Miao <13051207myq@gmail.com> Date: Mon, 12 May 2025 21:20:28 +0800 Subject: [PATCH] Implement client-side placeholder handling for empty recipe grid and remove server-side conditional rendering --- static/js/utils/VirtualScroller.js | 72 ++++++++++++++++++++++++++++++ templates/recipes.html | 39 +--------------- 2 files changed, 74 insertions(+), 37 deletions(-) diff --git a/static/js/utils/VirtualScroller.js b/static/js/utils/VirtualScroller.js index 8be0b288..83f954dd 100644 --- a/static/js/utils/VirtualScroller.js +++ b/static/js/utils/VirtualScroller.js @@ -194,6 +194,13 @@ export class VirtualScroller { // Update the spacer height based on the total number of items this.updateSpacerHeight(); + // Check if there are no items and show placeholder if needed + if (this.items.length === 0) { + this.showNoItemsPlaceholder(); + } else { + this.removeNoItemsPlaceholder(); + } + // Reset page state to sync with our virtual scroller pageState.currentPage = 2; // Next page to load would be 2 pageState.hasMore = this.hasMore; @@ -202,6 +209,7 @@ export class VirtualScroller { return { items, totalItems, hasMore }; } catch (err) { console.error('Failed to load initial batch:', err); + this.showNoItemsPlaceholder('Failed to load items. Please try refreshing the page.'); throw err; } finally { this.isLoading = false; @@ -387,6 +395,13 @@ export class VirtualScroller { this.hasMore = hasMore; this.updateSpacerHeight(); + // Check if there are no items and show placeholder if needed + if (this.items.length === 0) { + this.showNoItemsPlaceholder(); + } else { + this.removeNoItemsPlaceholder(); + } + // Clear all rendered items and redraw this.clearRenderedItems(); this.scheduleRender(); @@ -564,6 +579,9 @@ export class VirtualScroller { // Reset spacer height this.spacerElement.style.height = '0px'; + // Remove any placeholder + this.removeNoItemsPlaceholder(); + // Schedule a re-render this.scheduleRender(); } @@ -591,6 +609,60 @@ export class VirtualScroller { this.clearLoadingTimeout(); } + // Add methods to handle placeholder display + showNoItemsPlaceholder(message) { + // Remove any existing placeholder first + this.removeNoItemsPlaceholder(); + + // Create placeholder message + const placeholder = document.createElement('div'); + placeholder.className = 'placeholder-message'; + + // Determine appropriate message based on page type + let placeholderText = ''; + + if (message) { + placeholderText = message; + } else { + const pageType = state.currentPageType; + + if (pageType === 'recipes') { + placeholderText = ` +
No recipes found
+Add recipe images to your recipes folder to see them here.
+ `; + } else if (pageType === 'loras') { + placeholderText = ` +No LoRAs found
+Add LoRAs to your models folder to see them here.
+ `; + } else if (pageType === 'checkpoints') { + placeholderText = ` +No checkpoints found
+Add checkpoints to your models folder to see them here.
+ `; + } else { + placeholderText = ` +No items found
+Try adjusting your search filters or add more content.
+ `; + } + } + + placeholder.innerHTML = placeholderText; + placeholder.id = 'virtualScrollPlaceholder'; + + // Append placeholder to the grid + this.gridElement.appendChild(placeholder); + } + + removeNoItemsPlaceholder() { + const placeholder = document.getElementById('virtualScrollPlaceholder'); + if (placeholder) { + placeholder.remove(); + } + } + // Utility method for debouncing debounce(func, wait) { let timeout; diff --git a/templates/recipes.html b/templates/recipes.html index c8f9269f..b6d921c5 100644 --- a/templates/recipes.html +++ b/templates/recipes.html @@ -77,43 +77,8 @@