Update Style Controls

This commit is contained in:
Justin Deal 2025-05-03 13:35:55 -07:00
parent 583461d25c
commit fb7ef4c464
5 changed files with 145 additions and 13 deletions

View File

@ -248,14 +248,16 @@ document.addEventListener('alpine:init', () => {
iconSizeValue: 2, // Slider value: 1=small, 2=medium, 3=large iconSizeValue: 2, // Slider value: 1=small, 2=medium, 3=large
iconSize: 'medium', // small, medium, large iconSize: 'medium', // small, medium, large
viewMode: 'grid', // grid or list viewMode: 'grid', // grid or list
displayMode: 'both', // both, image, or name
debounceTimeout: null, // For debouncing slider changes debounceTimeout: null, // For debouncing slider changes
init() { init() {
baseSearch.init.call(this); baseSearch.init.call(this);
// Apply initial icon size and view mode // Apply initial icon size, view mode, and display mode
this.applyIconSize(); this.applyIconSize();
this.applyViewMode(); this.applyViewMode();
this.applyDisplayMode();
}, },
// Icon size methods // Icon size methods
@ -331,6 +333,44 @@ document.addEventListener('alpine:init', () => {
// Add the new view mode class // Add the new view mode class
appList.classList.add(`view-mode-${this.viewMode}`); appList.classList.add(`view-mode-${this.viewMode}`);
// Update all category sections
document.querySelectorAll('.category-section').forEach(section => {
const gridContainer = section.querySelector('.grid');
if (gridContainer) {
// Update grid classes based on view mode
if (this.viewMode === 'grid') {
gridContainer.classList.remove('grid-cols-1');
gridContainer.classList.add('grid-cols-2', 'sm:grid-cols-3', 'lg:grid-cols-4');
} else {
gridContainer.classList.remove('grid-cols-2', 'sm:grid-cols-3', 'lg:grid-cols-4');
gridContainer.classList.add('grid-cols-1');
}
}
});
},
// Display mode methods
setDisplayMode(mode) {
this.displayMode = mode;
this.applyDisplayMode();
},
applyDisplayMode() {
const appList = document.getElementById('app-list');
if (!appList) return;
// Remove existing display mode classes
appList.classList.remove('display-both', 'display-image-only', 'display-name-only');
// Add the new display mode class
if (this.displayMode === 'image') {
appList.classList.add('display-image-only');
} else if (this.displayMode === 'name') {
appList.classList.add('display-name-only');
} else {
appList.classList.add('display-both');
}
// Update all category sections // Update all category sections
document.querySelectorAll('.category-section').forEach(section => { document.querySelectorAll('.category-section').forEach(section => {
const gridContainer = section.querySelector('.grid'); const gridContainer = section.querySelector('.grid');

View File

@ -49,6 +49,15 @@
if (e.altKey && e.key === 'g' && this.toggleViewMode) { if (e.altKey && e.key === 'g' && this.toggleViewMode) {
this.toggleViewMode(); this.toggleViewMode();
} }
// Alt+B, Alt+I, Alt+N for display modes
if (e.altKey && e.key === 'b' && this.setDisplayMode) {
this.setDisplayMode('both');
} else if (e.altKey && e.key === 'i' && this.setDisplayMode) {
this.setDisplayMode('image');
} else if (e.altKey && e.key === 'n' && this.setDisplayMode) {
this.setDisplayMode('name');
}
}); });
} }
}; };

View File

@ -76,6 +76,44 @@ const { name, href, img, alt } = Astro.props;
text-align: left; text-align: left;
} }
/* Display mode styles */
/* Default display mode (both) */
.service-icon-container, .service-name {
display: block;
}
/* Image only mode */
:global(.display-image-only) .service-name {
display: none;
}
:global(.display-image-only) .service-icon-container {
display: flex;
justify-content: center;
align-items: center;
}
/* Name only mode */
:global(.display-name-only) .service-icon-container {
display: none;
}
:global(.display-name-only) .service-name {
display: block;
margin-top: 0;
font-size: 1.1rem;
}
/* Adjust list view for different display modes */
:global(.view-mode-list.display-name-only) .service-card {
padding: 0.75rem 1rem;
}
:global(.view-mode-list.display-image-only) .service-card {
justify-content: center;
padding: 0.5rem;
}
/* Icon size adjustments with CSS variables for fine-grained control */ /* Icon size adjustments with CSS variables for fine-grained control */
:global(#app-list) { :global(#app-list) {
--icon-scale: 2; /* Default medium size */ --icon-scale: 2; /* Default medium size */

View File

@ -54,6 +54,51 @@ const {
</div> </div>
)} )}
{/* Display options selector */}
<div class="flex items-center gap-2">
<span class="text-sm zag-text-muted hidden sm:inline">Display:</span>
<div class="display-selector flex items-center gap-1 border-2 border-solid zag-border-b rounded-lg p-1 zag-bg zag-transition">
<button
@click="setDisplayMode('both')"
:class="displayMode === 'both' ? 'active-display' : 'inactive-display'"
class="p-1.5 transition-all rounded-md focus:outline-none focus:ring-2 focus:ring-current"
aria-label="Show both image and name"
title="Show both image and name (Alt+B)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" 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="12" rx="2" ry="2"></rect>
<line x1="3" y1="19" x2="21" y2="19"></line>
<line x1="3" y1="23" x2="21" y2="23"></line>
</svg>
</button>
<button
@click="setDisplayMode('image')"
:class="displayMode === 'image' ? 'active-display' : 'inactive-display'"
class="p-1.5 transition-all rounded-md focus:outline-none focus:ring-2 focus:ring-current"
aria-label="Show image only"
title="Show image only (Alt+I)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" 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="2" ry="2"></rect>
<circle cx="12" cy="12" r="3"></circle>
</svg>
</button>
<button
@click="setDisplayMode('name')"
:class="displayMode === 'name' ? 'active-display' : 'inactive-display'"
class="p-1.5 transition-all rounded-md focus:outline-none focus:ring-2 focus:ring-current"
aria-label="Show name only"
title="Show name only (Alt+N)"
>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="6" x2="21" y2="6"></line>
<line x1="3" y1="18" x2="21" y2="18"></line>
</svg>
</button>
</div>
</div>
{showViewSelector && ( {showViewSelector && (
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span class="text-sm zag-text-muted hidden sm:inline">View:</span> <span class="text-sm zag-text-muted hidden sm:inline">View:</span>
@ -86,14 +131,14 @@ const {
</div> </div>
<style> <style>
.size-selector, .view-selector { .size-selector, .view-selector, .display-selector {
box-shadow: 2px 2px 0 var(--color-zag-dark); box-shadow: 2px 2px 0 var(--color-zag-dark);
:where(.dark, .dark *) & { :where(.dark, .dark *) & {
box-shadow: 2px 2px 0 var(--color-zag-light); box-shadow: 2px 2px 0 var(--color-zag-light);
} }
} }
.active-size, .active-view { .active-size, .active-view, .active-display {
color: var(--color-zag-dark); color: var(--color-zag-dark);
background-color: var(--color-zag-light); background-color: var(--color-zag-light);
transform: translateY(-1px); transform: translateY(-1px);
@ -103,14 +148,14 @@ const {
} }
} }
.inactive-size, .inactive-view { .inactive-size, .inactive-view, .inactive-display {
color: var(--color-zag-dark-muted); color: var(--color-zag-dark-muted);
:where(.dark, .dark *) & { :where(.dark, .dark *) & {
color: var(--color-zag-light-muted); color: var(--color-zag-light-muted);
} }
} }
.inactive-size:hover, .inactive-view:hover { .inactive-size:hover, .inactive-view:hover, .inactive-display:hover {
background-color: var(--color-zag-light-muted); background-color: var(--color-zag-light-muted);
color: var(--color-zag-dark); color: var(--color-zag-dark);
:where(.dark, .dark *) & { :where(.dark, .dark *) & {

View File

@ -44,22 +44,22 @@ const webpageData = {
<!-- Keyboard shortcuts for style controls --> <!-- Keyboard shortcuts for style controls -->
<StyleControlsScript /> <StyleControlsScript />
<Section class="my-8"> <Section class="my-2">
<div x-data="searchServices" x-init="init()" x-cloak> <div x-data="searchServices" x-init="init()" x-cloak>
<!-- Search and controls container --> <!-- Search and controls container -->
<div class="mb-4 pt-0"> <div class="mb-4 pt-0">
<!-- Search bar in its own row --> <!-- Style controls in a centered row above search -->
<div class="w-full mb-3"> <div class="w-full flex justify-center mb-4">
<StyleControls />
</div>
<!-- Search bar below style controls -->
<div class="w-full">
<SearchBar <SearchBar
placeholder="Search services..." placeholder="Search services..."
ariaLabel="Search services" ariaLabel="Search services"
/> />
</div> </div>
<!-- Style controls in a row below search -->
<div class="w-full flex justify-end">
<StyleControls />
</div>
</div> </div>
<!-- Page heading - now below search --> <!-- Page heading - now below search -->