Compare commits

..

No commits in common. "b6df2f1a3456539bda72aff6e115be2cccb709bd" and "49e024343ec66caf46c687087c004c8a2d1893af" have entirely different histories.

7 changed files with 6 additions and 283 deletions

View File

@ -15,7 +15,6 @@
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
@ -24,9 +23,6 @@
// 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) {
@ -69,12 +65,6 @@
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) {
@ -89,7 +79,6 @@
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);
}
@ -248,110 +237,6 @@
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';
}
});
}
}
}
}));
@ -436,16 +321,6 @@
}));
}
});
// 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() {
@ -592,20 +467,7 @@
// Add the new view mode class
appList.classList.add(`view-mode-${this.viewMode}`);
// 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)
// Update all category sections
document.querySelectorAll('.category-section').forEach(section => {
const gridContainer = section.querySelector('.grid');
if (gridContainer) {

View File

@ -50,11 +50,6 @@
} 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();
}
}
});
});

View File

@ -31,7 +31,6 @@ const id = `scroll-reveal-${crypto.randomUUID().slice(0, 8)}`;
data-threshold={threshold}
data-root-margin={rootMargin}
data-once={once}
style="display: contents;"
>
<slot />
</div>

View File

@ -94,18 +94,15 @@ const cardId = `service-card-${crypto.randomUUID().slice(0, 8)}`;
overflow: hidden;
position: relative;
/* Enhanced transitions for smoother mode changes */
/* Transitions */
transition:
transform var(--card-transition-duration) var(--card-transition-timing),
box-shadow var(--card-transition-duration) var(--card-transition-timing),
border-color var(--card-transition-duration) var(--card-transition-timing),
border var(--card-transition-duration) var(--card-transition-timing),
background-color var(--card-transition-duration) var(--card-transition-timing),
opacity var(--card-transition-duration) var(--card-transition-timing),
padding var(--card-transition-duration) var(--card-transition-timing);
background-color var(--card-transition-duration) var(--card-transition-timing);
/* Performance optimizations */
will-change: transform, box-shadow, border-color, background-color, opacity;
will-change: transform, box-shadow, border-color;
}
/* Gradient background effect */
@ -142,18 +139,6 @@ const cardId = `service-card-${crypto.randomUUID().slice(0, 8)}`;
transform var(--card-transition-duration) var(--card-transition-timing);
}
/* Enhanced background glow in image-only mode */
:global(.display-image-only) .service-icon-background {
transition:
opacity calc(var(--card-transition-duration) * 1.5) var(--card-transition-timing),
transform calc(var(--card-transition-duration) * 1.5) var(--card-transition-timing);
}
:global(.display-image-only) .service-card:hover .service-icon-background {
opacity: 0.25;
transform: scale(1.8);
}
/* Icon image */
.service-icon {
width: var(--icon-size);
@ -165,18 +150,6 @@ const cardId = `service-card-${crypto.randomUUID().slice(0, 8)}`;
filter var(--card-transition-duration) var(--card-transition-timing);
}
/* Special icon animation for image-only mode */
:global(.display-image-only) .service-icon {
transition:
transform calc(var(--card-transition-duration) * 1.2) var(--card-transition-timing),
filter var(--card-transition-duration) var(--card-transition-timing);
}
:global(.display-image-only) .service-card:hover .service-icon {
transform: scale(1.15) rotate(3deg);
filter: drop-shadow(0 6px 8px rgba(0, 0, 0, 0.15));
}
/* Service name */
.service-name {
margin-top: 0.5rem;
@ -256,39 +229,6 @@ const cardId = `service-card-${crypto.randomUUID().slice(0, 8)}`;
display: flex;
justify-content: center;
align-items: center;
transform: translateY(0);
transition:
transform var(--card-transition-duration) var(--card-transition-timing),
filter var(--card-transition-duration) var(--card-transition-timing);
}
/* Enhanced icon effects in image-only mode */
:global(.display-image-only) .service-card:hover .service-icon-container {
transform: translateY(-2px) scale(1.02);
}
/* 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;
transform: scale(1.01);
padding: 0.5rem;
}
/* Adjust hover/active states in image-only mode */
:global(.display-image-only) .service-card:hover {
transform: translateY(-4px) scale(1.03);
border-color: transparent;
background-color: transparent;
box-shadow: none;
}
:global(.display-image-only) .service-card:hover::before,
:global(.display-image-only) .service-card::before {
opacity: 0;
display: none;
}
/* Name only mode */

View File

@ -107,30 +107,6 @@ const {
</div>
</div>
)}
{/* Grouping toggle */}
<div class="flex items-center gap-2">
<span class="text-sm zag-text-muted hidden sm:inline">Group:</span>
<div class="grouping-selector border-2 border-solid zag-border-b rounded-lg p-1 zag-bg zag-transition">
<button
@click="toggleGrouping"
:class="groupByCategory ? 'active-view' : 'inactive-view'"
class="p-1.5 transition-all rounded-md focus:outline-none focus:ring-2 focus:ring-current"
aria-label="Toggle category grouping"
:title="groupByCategory ? 'Show all apps together' : 'Group by category'"
>
<!-- Icon for grouped view (shows when grouping is active) -->
<svg x-show="groupByCategory" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="18" height="7" rx="1"></rect>
<rect x="3" y="14" width="18" height="7" rx="1"></rect>
</svg>
<!-- Icon for ungrouped view (shows when grouping is inactive) -->
<svg x-show="!groupByCategory" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="18" height="18" rx="1"></rect>
</svg>
</button>
</div>
</div>
</div>
<style>

View File

@ -79,7 +79,7 @@ const categoryLower = category.toLowerCase();
x-transition:leave-end="opacity-0 transform -translate-y-4"
id={categoryId}
>
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-6 transition-all duration-300">
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-4 transition-all duration-300">
{apps.length > 0 ? (
apps.map(app => {
const appName = app.name.toLowerCase();

View File

@ -40,57 +40,8 @@ const webpageData = {
/>
<StructuredData slot="head" type="WebPage" data={webpageData} />
<!-- Print-specific styles and no-grouping styles -->
<!-- Print-specific styles -->
<style is:global slot="head">
/* No grouping styles - completely overhauled grid layout */
:global(.no-category-grouping) .category-section {
margin: 0 !important;
padding: 0 !important;
}
:global(.no-category-grouping) .category-section:not(:first-child) {
margin: 0 !important;
}
/* When a category section has the no-grouping class */
.category-section.no-grouping {
margin: 0 !important;
padding: 0 !important;
}
/* Create a unified grid container for all items in ungrouped mode */
:global(.no-category-grouping) #app-list {
display: grid !important;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)) !important;
gap: 1.5rem !important; /* Force equal spacing in both directions */
row-gap: 1.5rem !important; /* Explicitly set row gap */
column-gap: 1.5rem !important; /* Explicitly set column gap */
width: 100% !important;
padding: 0.75rem !important; /* Add some padding around the entire grid */
}
/* Completely flatten grid to be a single container in ungrouped mode */
:global(.no-category-grouping) .grid {
display: contents !important; /* Make grid container act as its children */
margin: 0 !important;
padding: 0 !important;
gap: 0 !important;
}
/* Fix each app card to ensure proper layout in the grid */
:global(.no-category-grouping) .app-card {
height: 100% !important;
margin: 0 !important;
}
/* Fix ScrollReveal containers in no-grouping mode */
:global(.no-category-grouping) .scroll-reveal {
height: 100% !important;
margin: 0 !important;
padding: 0 !important;
}
/* Print styles */
@media print {
/* Hide non-essential UI elements */
header, footer, .search-container, .style-controls, button[aria-controls] {