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
iconSize: 'medium', // small, medium, large
viewMode: 'grid', // grid or list
displayMode: 'both', // both, image, or name
debounceTimeout: null, // For debouncing slider changes
init() {
baseSearch.init.call(this);
// Apply initial icon size and view mode
// Apply initial icon size, view mode, and display mode
this.applyIconSize();
this.applyViewMode();
this.applyDisplayMode();
},
// Icon size methods
@ -331,6 +333,44 @@ document.addEventListener('alpine:init', () => {
// Add the new view mode class
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
document.querySelectorAll('.category-section').forEach(section => {
const gridContainer = section.querySelector('.grid');

View File

@ -49,6 +49,15 @@
if (e.altKey && e.key === 'g' && 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;
}
/* 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 */
:global(#app-list) {
--icon-scale: 2; /* Default medium size */

View File

@ -54,6 +54,51 @@ const {
</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 && (
<div class="flex items-center gap-2">
<span class="text-sm zag-text-muted hidden sm:inline">View:</span>
@ -86,14 +131,14 @@ const {
</div>
<style>
.size-selector, .view-selector {
.size-selector, .view-selector, .display-selector {
box-shadow: 2px 2px 0 var(--color-zag-dark);
:where(.dark, .dark *) & {
box-shadow: 2px 2px 0 var(--color-zag-light);
}
}
.active-size, .active-view {
.active-size, .active-view, .active-display {
color: var(--color-zag-dark);
background-color: var(--color-zag-light);
transform: translateY(-1px);
@ -103,14 +148,14 @@ const {
}
}
.inactive-size, .inactive-view {
.inactive-size, .inactive-view, .inactive-display {
color: var(--color-zag-dark-muted);
:where(.dark, .dark *) & {
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);
color: var(--color-zag-dark);
:where(.dark, .dark *) & {

View File

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