Add sticky filter improvements and unified filter input styling
- Change sticky filter visibility check to use reset button position - Add reset button to sticky filter (centered, below filter grid) - Reset filters now resets map to initial position if no results - Unify select/input styling: same height, black background, consistent borders
This commit is contained in:
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Regular → Executable
+3
@@ -95,5 +95,8 @@ $mls_cities = homeproz_get_mls_cities(50);
|
||||
<input type="text" name="zip" class="filter-input" placeholder="Zip" value="<?php echo esc_attr($current_zip); ?>" maxlength="10" pattern="[0-9\-]*" aria-label="Zip Code">
|
||||
</div>
|
||||
</div>
|
||||
<div class="filters-sticky-reset">
|
||||
<a href="<?php echo esc_url(get_post_type_archive_link('property')); ?>" class="btn btn-secondary filters-reset">Reset</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -281,6 +281,8 @@
|
||||
baseZIndex: 400,
|
||||
currentFilters: {},
|
||||
currentMode: null, // Track current visualization mode
|
||||
initialCenter: [45.0, -93.5], // Initial map center (Minnesota)
|
||||
initialZoom: 7, // Initial zoom level
|
||||
|
||||
/**
|
||||
* Initialize the map
|
||||
@@ -683,6 +685,15 @@
|
||||
this.loadClusters();
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset map to initial position (Minnesota overview)
|
||||
*/
|
||||
resetToInitialPosition: function() {
|
||||
if (this.map) {
|
||||
this.map.setView(this.initialCenter, this.initialZoom);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Format number with commas
|
||||
*/
|
||||
@@ -895,7 +906,9 @@
|
||||
$stickyFilter: null,
|
||||
$mainForm: null,
|
||||
$stickyForm: null,
|
||||
observer: null,
|
||||
$resetButton: null,
|
||||
$masthead: null,
|
||||
scrollTimeout: null,
|
||||
isVisible: false,
|
||||
|
||||
/**
|
||||
@@ -911,38 +924,49 @@
|
||||
this.$stickyFilter = $('#property-filters-sticky');
|
||||
this.$mainForm = this.$mainFilter.find('.filters-form');
|
||||
this.$stickyForm = this.$stickyFilter.find('.filters-form-sticky');
|
||||
this.$resetButton = this.$mainFilter.find('.filter-item-button .btn');
|
||||
this.$masthead = $('#masthead');
|
||||
|
||||
if (!this.$mainFilter.length || !this.$stickyFilter.length) {
|
||||
if (!this.$mainFilter.length || !this.$stickyFilter.length || !this.$resetButton.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setupObserver();
|
||||
this.setupScrollHandler();
|
||||
this.bindEvents();
|
||||
// Check initial state
|
||||
this.checkVisibility();
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup IntersectionObserver on main filter
|
||||
* Setup scroll handler to check reset button visibility
|
||||
* Sticky filter shows when reset button's bottom edge is above (masthead + 10px)
|
||||
*/
|
||||
setupObserver: function() {
|
||||
setupScrollHandler: function() {
|
||||
var self = this;
|
||||
|
||||
this.observer = new IntersectionObserver(function(entries) {
|
||||
entries.forEach(function(entry) {
|
||||
if (entry.isIntersecting) {
|
||||
// Main filter is visible - hide sticky (instant)
|
||||
self.hideStickyFilter();
|
||||
} else {
|
||||
// Main filter scrolled out - show sticky (animated)
|
||||
self.showStickyFilter();
|
||||
}
|
||||
});
|
||||
}, {
|
||||
root: null,
|
||||
rootMargin: '0px',
|
||||
threshold: 0
|
||||
$(window).on('scroll.stickyFilters', function() {
|
||||
clearTimeout(self.scrollTimeout);
|
||||
self.scrollTimeout = setTimeout(function() {
|
||||
self.checkVisibility();
|
||||
}, 50);
|
||||
});
|
||||
},
|
||||
|
||||
this.observer.observe(this.$mainFilter[0]);
|
||||
/**
|
||||
* Check if main filter is obscured and toggle sticky visibility
|
||||
* Obscured = reset button bottom edge is above (viewport top + masthead height + 10px)
|
||||
*/
|
||||
checkVisibility: function() {
|
||||
var mastheadHeight = this.$masthead.length ? this.$masthead.outerHeight() : 0;
|
||||
var threshold = mastheadHeight + 10;
|
||||
var resetButtonRect = this.$resetButton[0].getBoundingClientRect();
|
||||
|
||||
// Reset button is obscured when its bottom edge is above the threshold
|
||||
if (resetButtonRect.bottom < threshold) {
|
||||
this.showStickyFilter();
|
||||
} else {
|
||||
this.hideStickyFilter();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -956,6 +980,22 @@
|
||||
self.syncToSticky(this.name, $(this).val());
|
||||
});
|
||||
|
||||
// City/Zip mutual exclusivity in sticky form - city clears zip
|
||||
this.$stickyForm.find('select[name="property_location"]').on('change', function() {
|
||||
if ($(this).val()) {
|
||||
self.$stickyForm.find('input[name="zip"]').val('');
|
||||
self.$mainForm.find('input[name="zip"]').val('');
|
||||
}
|
||||
});
|
||||
|
||||
// City/Zip mutual exclusivity in sticky form - zip clears city
|
||||
this.$stickyForm.find('input[name="zip"]').on('input', function() {
|
||||
if ($(this).val()) {
|
||||
self.$stickyForm.find('select[name="property_location"]').val('');
|
||||
self.$mainForm.find('select[name="property_location"]').val('');
|
||||
}
|
||||
});
|
||||
|
||||
// Sync sticky form -> main form and trigger filter
|
||||
this.$stickyForm.find('select').on('change', function() {
|
||||
self.syncToMain(this.name, $(this).val());
|
||||
@@ -1047,6 +1087,7 @@
|
||||
mapBounds: null, // Current map viewport bounds
|
||||
mapCenter: null, // Current map center for distance sorting
|
||||
isMapUpdate: false, // Flag to prevent map->filter->map loop
|
||||
isResetTriggered: false, // Flag: true when reset button was clicked
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
@@ -1076,6 +1117,34 @@
|
||||
self.filterProperties(1);
|
||||
});
|
||||
|
||||
// City/Zip mutual exclusivity - city clears zip
|
||||
this.$form.find('select[name="property_location"]').on('change', function() {
|
||||
if ($(this).val()) {
|
||||
self.$form.find('input[name="zip"]').val('');
|
||||
// Also sync to sticky form if it exists
|
||||
if (StickyFilters && StickyFilters.$stickyForm) {
|
||||
StickyFilters.$stickyForm.find('input[name="zip"]').val('');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// City/Zip mutual exclusivity - zip clears city
|
||||
this.$form.find('input[name="zip"]').on('input', function() {
|
||||
if ($(this).val()) {
|
||||
self.$form.find('select[name="property_location"]').val('');
|
||||
// Also sync to sticky form if it exists
|
||||
if (StickyFilters && StickyFilters.$stickyForm) {
|
||||
StickyFilters.$stickyForm.find('select[name="property_location"]').val('');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Zip code submit on enter or blur
|
||||
this.$form.find('input[name="zip"]').on('change', function() {
|
||||
self.clearPinSelection();
|
||||
self.onFilterChange();
|
||||
});
|
||||
|
||||
// Filter changes (auto-submit on select change)
|
||||
this.$form.find('select').on('change', function() {
|
||||
self.clearPinSelection();
|
||||
@@ -1480,6 +1549,10 @@
|
||||
var wasMapUpdate = this.isMapUpdate;
|
||||
this.isMapUpdate = false;
|
||||
|
||||
// Capture and clear reset flag
|
||||
var wasResetTriggered = this.isResetTriggered;
|
||||
this.isResetTriggered = false;
|
||||
|
||||
// Queue the property list request with debounce and cancellation
|
||||
RequestQueue.queue(
|
||||
'properties',
|
||||
@@ -1495,6 +1568,11 @@
|
||||
self.$results.html(response.data.html);
|
||||
self.isFirstLoad = false;
|
||||
|
||||
// If reset was triggered and no results, reset map to initial position
|
||||
if (wasResetTriggered && response.data.found_posts === 0 && PropertyMap.map) {
|
||||
PropertyMap.resetToInitialPosition();
|
||||
}
|
||||
|
||||
// Update map with new filter params (but not if this was triggered by map move)
|
||||
if (response.data.filters && !wasMapUpdate) {
|
||||
PropertyMap.updateFilters(response.data.filters);
|
||||
@@ -1681,9 +1759,24 @@
|
||||
|
||||
/**
|
||||
* Reset filters
|
||||
* Clears all form fields and triggers reload.
|
||||
* If no results after reset, map resets to initial position.
|
||||
*/
|
||||
resetFilters: function() {
|
||||
// Clear all selects
|
||||
this.$form.find('select').val('');
|
||||
// Clear zip input
|
||||
this.$form.find('input[name="zip"]').val('');
|
||||
|
||||
// Also sync to sticky form
|
||||
if (StickyFilters && StickyFilters.$stickyForm) {
|
||||
StickyFilters.$stickyForm.find('select').val('');
|
||||
StickyFilters.$stickyForm.find('input[name="zip"]').val('');
|
||||
}
|
||||
|
||||
// Set flag for reset-triggered request
|
||||
this.isResetTriggered = true;
|
||||
|
||||
this.onFilterChange();
|
||||
},
|
||||
|
||||
|
||||
@@ -473,19 +473,17 @@
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
.filter-select {
|
||||
.filter-select,
|
||||
.filter-input {
|
||||
width: 100%;
|
||||
padding: 0.625rem 2rem 0.625rem 0.75rem;
|
||||
background-color: var(--color-bg-dark);
|
||||
height: 2.75rem;
|
||||
padding: 0 0.75rem;
|
||||
background-color: #000;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.25rem;
|
||||
color: var(--color-text);
|
||||
font-size: 0.9375rem;
|
||||
cursor: pointer;
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23B0B0B0' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.75rem center;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
@@ -493,24 +491,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
.filter-input {
|
||||
width: 100%;
|
||||
padding: 0.625rem 0.75rem;
|
||||
background-color: var(--color-bg-dark);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.25rem;
|
||||
color: var(--color-text);
|
||||
font-size: 0.9375rem;
|
||||
.filter-select {
|
||||
padding-right: 2rem;
|
||||
cursor: pointer;
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23B0B0B0' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.75rem center;
|
||||
}
|
||||
|
||||
.filter-input {
|
||||
&::placeholder {
|
||||
color: var(--color-text-muted);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
}
|
||||
|
||||
// Zip code filter - narrower width
|
||||
@@ -571,12 +565,14 @@
|
||||
.filter-select,
|
||||
.filter-input {
|
||||
width: 100%;
|
||||
padding: 0.5rem 0.625rem;
|
||||
height: 2.25rem;
|
||||
padding: 0 0.625rem;
|
||||
font-size: 0.8125rem;
|
||||
background-color: var(--color-bg-dark);
|
||||
background-color: #000;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.25rem;
|
||||
color: var(--color-text);
|
||||
box-sizing: border-box;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
@@ -602,6 +598,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
.filters-sticky-reset {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 0.75rem;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid var(--color-border);
|
||||
|
||||
.btn {
|
||||
padding: 0.5rem 1.5rem;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Results loading spinner (only for first load)
|
||||
.property-results-loading {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user