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;"
>