diff --git a/src/components/SearchScript.astro b/src/components/SearchScript.astro index 6ab8cfc..cd80840 100644 --- a/src/components/SearchScript.astro +++ b/src/components/SearchScript.astro @@ -15,6 +15,7 @@ iconSizeValue: 2, // Slider value: 1=small, 2=medium, 3=large viewMode: 'grid', displayMode: 'both', + groupByCategory: false, // Whether to group services by category (default: ungrouped) init() { // Load preferences from localStorage @@ -23,6 +24,9 @@ // Set initial iconSizeValue based on iconSize this.updateSliderFromIconSize(); + // Apply initial grouping mode + this.applyGroupingModeDirectly(this.groupByCategory); + // Listen for events from searchServices component window.addEventListener('styleControls:updateIconSize', (e) => { if (e.detail && e.detail.size) { @@ -65,6 +69,12 @@ this.displayMode = savedDisplayMode; } + // Load grouping preference + const savedGrouping = localStorage.getItem('services-group-by-category'); + if (savedGrouping !== null) { + this.groupByCategory = savedGrouping === 'true'; + } + // Update slider value based on loaded icon size this.updateSliderFromIconSize(); } catch (e) { @@ -79,6 +89,7 @@ localStorage.setItem('services-icon-size', this.iconSize); localStorage.setItem('services-view-mode', this.viewMode); localStorage.setItem('services-display-mode', this.displayMode); + localStorage.setItem('services-group-by-category', this.groupByCategory); } catch (e) { console.error('Error saving preferences:', e); } @@ -237,6 +248,110 @@ appList.classList.add('display-both'); } } + }, + + // Toggle grouping of services by category + toggleGrouping() { + this.groupByCategory = !this.groupByCategory; + this.savePreferences(); + + // Apply grouping mode directly with DOM restructuring + this.applyGroupingModeDirectly(this.groupByCategory); + + // Dispatch event to notify searchServices component + window.dispatchEvent(new CustomEvent('searchServices:setGrouping', { + detail: { groupByCategory: this.groupByCategory } + })); + }, + + // Apply grouping mode directly to DOM elements with full restructuring + applyGroupingModeDirectly(groupByCategory) { + console.log('Applying grouping mode directly:', groupByCategory); + const appList = document.getElementById('app-list'); + if (appList) { + // Toggle class on app-list for any global styling + appList.classList.toggle('no-category-grouping', !groupByCategory); + + if (groupByCategory) { + // GROUPED MODE: Restore original category structure + + // Get unified grid if it exists + const unifiedGrid = document.getElementById('unified-grid-container'); + if (unifiedGrid) { + // Get all card wrappers in unified grid (these are the ScrollReveal containers) + const cardWrappers = Array.from(unifiedGrid.querySelectorAll('.scroll-reveal')); + + // Show all category sections + document.querySelectorAll('.category-section').forEach(section => { + section.classList.remove('no-grouping'); + section.style.display = ''; + const categoryTitle = section.querySelector('.category-toggle'); + if (categoryTitle) categoryTitle.style.display = ''; + }); + + // Move each card wrapper back to its original category + cardWrappers.forEach(wrapper => { + // Find the app card inside the wrapper + const card = wrapper.querySelector('.app-card'); + if (card) { + const categoryName = card.getAttribute('data-app-category'); + if (categoryName) { + const originalSection = document.querySelector(`.category-section[data-category="${categoryName}"]`); + if (originalSection) { + const gridContainer = originalSection.querySelector('.grid'); + if (gridContainer) { + // Move the wrapper back to its original grid + gridContainer.appendChild(wrapper); + } + } + } + } + }); + + // Remove unified grid + unifiedGrid.remove(); + } + } else { + // UNGROUPED MODE: Create single unified grid + + // Create unified grid if it doesn't exist + let unifiedGrid = document.getElementById('unified-grid-container'); + if (!unifiedGrid) { + unifiedGrid = document.createElement('div'); + unifiedGrid.id = 'unified-grid-container'; + unifiedGrid.className = 'grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-6'; + // Add any necessary styles directly to ensure consistent spacing + unifiedGrid.style.gap = '1.5rem'; + unifiedGrid.style.padding = '0.5rem'; + appList.appendChild(unifiedGrid); + } + + // Process each category section + document.querySelectorAll('.category-section').forEach(section => { + section.classList.add('no-grouping'); + const categoryTitle = section.querySelector('.category-toggle'); + if (categoryTitle) categoryTitle.style.display = 'none'; + + // Ensure all categories are expanded + if (section.__x) { + section.__x.$data.open = true; + } + + // Get all card wrappers in this category (these are the ScrollReveal containers) + const cardWrappers = Array.from(section.querySelectorAll('.scroll-reveal')); + + // Move all card wrappers to unified grid + cardWrappers.forEach(wrapper => { + unifiedGrid.appendChild(wrapper); + }); + + // Hide the now-empty category section + if (cardWrappers.length > 0) { + section.style.display = 'none'; + } + }); + } + } } })); @@ -321,6 +436,16 @@ })); } }); + + // Listen for grouping changes + window.addEventListener('searchServices:setGrouping', (e) => { + if (e.detail && e.detail.groupByCategory !== undefined) { + console.log('searchServices received grouping event:', e.detail.groupByCategory); + + // Update any searchServices related functionality if needed + // This is primarily handled by styleControls but can be extended here + } + }); }, setupWatchers() { @@ -467,7 +592,20 @@ // Add the new view mode class appList.classList.add(`view-mode-${this.viewMode}`); - // Update all category sections + // Check for unified grid (in ungrouped mode) + const unifiedGrid = document.getElementById('unified-grid-container'); + if (unifiedGrid) { + // Update unified grid classes based on view mode + if (this.viewMode === 'grid') { + unifiedGrid.classList.remove('grid-cols-1'); + unifiedGrid.classList.add('grid-cols-2', 'sm:grid-cols-3', 'lg:grid-cols-4'); + } else { + unifiedGrid.classList.remove('grid-cols-2', 'sm:grid-cols-3', 'lg:grid-cols-4'); + unifiedGrid.classList.add('grid-cols-1'); + } + } + + // Update all category sections (for grouped mode) document.querySelectorAll('.category-section').forEach(section => { const gridContainer = section.querySelector('.grid'); if (gridContainer) { diff --git a/src/components/StyleControlsScript.astro b/src/components/StyleControlsScript.astro index c8452eb..9baac60 100644 --- a/src/components/StyleControlsScript.astro +++ b/src/components/StyleControlsScript.astro @@ -50,6 +50,11 @@ } else if (e.altKey && e.key === 'n' && styleComponent.setDisplayMode) { styleComponent.setDisplayMode('name'); } + + // Alt+C for category grouping toggle + if (e.altKey && e.key === 'c' && styleComponent.toggleGrouping) { + styleComponent.toggleGrouping(); + } } }); }); diff --git a/src/components/common/ScrollReveal.astro b/src/components/common/ScrollReveal.astro index 96e9b0a..900967a 100644 --- a/src/components/common/ScrollReveal.astro +++ b/src/components/common/ScrollReveal.astro @@ -31,6 +31,7 @@ const id = `scroll-reveal-${crypto.randomUUID().slice(0, 8)}`; data-threshold={threshold} data-root-margin={rootMargin} data-once={once} + style="display: contents;" > diff --git a/src/components/common/ServiceCard.astro b/src/components/common/ServiceCard.astro index 9dfb820..d7e4026 100644 --- a/src/components/common/ServiceCard.astro +++ b/src/components/common/ServiceCard.astro @@ -267,14 +267,14 @@ const cardId = `service-card-${crypto.randomUUID().slice(0, 8)}`; transform: translateY(-2px) scale(1.02); } - /* Smooth animation for card background in image-only mode */ + /* Completely hide card background in image-only mode */ :global(.display-image-only) .service-card { background-color: transparent; border-color: transparent; border-width: 0; box-shadow: none; - /* Add slight scale effect during transition */ transform: scale(1.01); + padding: 0.5rem; } /* Adjust hover/active states in image-only mode */ @@ -285,8 +285,10 @@ const cardId = `service-card-${crypto.randomUUID().slice(0, 8)}`; box-shadow: none; } - :global(.display-image-only) .service-card:hover::before { + :global(.display-image-only) .service-card:hover::before, + :global(.display-image-only) .service-card::before { opacity: 0; + display: none; } /* Name only mode */ diff --git a/src/components/common/StyleControls.astro b/src/components/common/StyleControls.astro index 328d865..d8a0cc0 100644 --- a/src/components/common/StyleControls.astro +++ b/src/components/common/StyleControls.astro @@ -107,6 +107,30 @@ const { )} + + {/* Grouping toggle */} +
+ +
+ +
+