theme sync

This commit is contained in:
2024-04-08 06:32:26 -04:00
parent 74d73feffa
commit 67e0407058
13 changed files with 844 additions and 419 deletions

View File

@@ -2787,6 +2787,21 @@ html {
background-color: rgb(87 83 78/var(--tw-bg-opacity)); background-color: rgb(87 83 78/var(--tw-bg-opacity));
} }
.hover\:bg-stone-100:hover {
--tw-bg-opacity: 1;
background-color: rgb(245 245 244/var(--tw-bg-opacity));
}
.hover\:bg-stone-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(231 229 228/var(--tw-bg-opacity));
}
.hover\:bg-stone-300:hover {
--tw-bg-opacity: 1;
background-color: rgb(214 211 209/var(--tw-bg-opacity));
}
.hover\:text-white:hover { .hover\:text-white:hover {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(255 255 255/var(--tw-text-opacity)); color: rgb(255 255 255/var(--tw-text-opacity));

View File

@@ -106,4 +106,136 @@ li.autocart-filters:hover {
.bg-custom-red-opacity { .bg-custom-red-opacity {
background-color: rgb(150 29 32 / 30%); background-color: rgb(150 29 32 / 30%);
} }
.mdc-list-item {
height: 48px;
display: -ms-flexbox;
display: flex;
position: relative;
-ms-flex-align: center;
align-items: center;
-ms-flex-pack: start;
justify-content: flex-start;
padding: 0 16px;
overflow: hidden;
}
.mdc-select:not(.mdc-select--disabled).mdc-select--focused .mdc-floating-label {
color: var(--mdc-theme-primary) !important;
}
li.mdc-list-item:hover {
background-color:var(--mdc-theme-primary);
color: #fff;
}
.btn-process {
font-size: 2rem;
font-family: 'Montserrat', sans-serif;
background-color: #256EFF;
box-shadow: 0px 15px 27px 2px rgba(37, 110, 255, 0.28);
border: none;
outline: none;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 1rem 3rem;
border-radius: 1rem;
color: #fff;
cursor: pointer;
}
.btn-ring:after {
content: "";
display: block;
width: 25px;
height: 25px;
margin: 0 8px;
border-radius: 50%;
border: 3px solid #fff;
border-color: #fff transparent #fff transparent;
animation: ring 1.2s linear infinite;
}
@keyframes ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.btn-ring.loading {
display: inline-block;
}
.loading .btn-ring {
display: block;
}
.ac-accordion-content {
padding: 10px;
display: block; /* Start with display: block to ensure proper height transition */
overflow: hidden; /* Hide overflowing content */
transition: height 0.3s ease; /* Add transition for height */
}
.collapsed .ac-accordion-content {
height: 0; /* Collapse the content by setting height to 0 */
padding-top: 0;
padding-bottom: 0;
transition: height 0.3s ease; /* Add transition for height */
}
.order-mobile-first {
order: 2;
}
.order-mobile-second {
order: 1;
}
/* Web Order (Normal order on larger screens) */
.order-web-first {
order: 1;
}
.order-web-second {
order: 2;
}
#slide-out-filters{
transition: 300ms ease-in-out;
translate: -100%;
}
/* Styles for screens wider than 768px (web view) */
@media screen and (min-width: 768px) {
.container {
width: 70%;
margin: 0 auto;
}
h1 {
font-size: 2em;
}
#slide-out-filters{
translate: 0;
translate: 0px;
position: static;
z-index: 40;
width: 25%;
}
}
/* Styles for screens narrower than 768px (mobile view) */
@media screen and (max-width: 768px) {
.sticky-container{
position: static;
}
}

View File

@@ -83,4 +83,47 @@ class DataStore {
this.notifySubscribers(); this.notifySubscribers();
} }
sortByFinance(order) {
this.vehicles.sort((a, b) => {
const aValue = this.calculateFinance(a);
const bValue = this.calculateFinance(b);
if (order === 'asc') {
return aValue.payment - bValue.payment;
} else {
return bValue.payment - aValue.payment;
}
});
this.notifySubscribers();
}
calculateFinance(vehicle) {
let annInterest = 7.99;
let monInt = annInterest / 1200;
let months = 12;
let amount = vehicle.advertise_price;
let down = 0;
let trade = 0;
var financeTotal = amount - (down + trade);
var numberOfPayments = months / (12 / 26);
var interest = financeTotal * (annInterest / 26) * numberOfPayments;
var additionalFees = 0;
var totalCostOfCredit = interest + additionalFees;
var totalObligation = financeTotal + totalCostOfCredit;
var payment = ((monInt + (monInt / (Math.pow((1 + monInt), months) - 1))) * (amount - (down || 0)) / 2).toFixed(2);
return {
financeTotal: financeTotal,
numberOfPayments: numberOfPayments,
interest: interest,
additionalFees: additionalFees,
totalCostOfCredit: totalCostOfCredit,
totalObligation: totalObligation,
payment: parseFloat(payment) // Convert payment to a number
};
}
} }

View File

@@ -10,7 +10,9 @@ class SortBy {
{ field: 'make', order: 'asc', label: 'Make Name: A to Z' }, { field: 'make', order: 'asc', label: 'Make Name: A to Z' },
{ field: 'make', order: 'desc', label: 'Make Name: Z to A' }, { field: 'make', order: 'desc', label: 'Make Name: Z to A' },
{ field: 'model', order: 'asc', label: 'Model Name: A to Z' }, { field: 'model', order: 'asc', label: 'Model Name: A to Z' },
{ field: 'model', order: 'desc', label: 'Model Name: Z to A' } { field: 'model', order: 'desc', label: 'Model Name: Z to A' },
{ field: 'finance', order: 'asc', label: 'Finance: Low to High' },
{ field: 'finance', order: 'desc', label: 'Finance: High to Low' }
]; ];
this.init(); this.init();
} }
@@ -50,6 +52,11 @@ class SortBy {
const selectedOption = this.sortByElement.value; const selectedOption = this.sortByElement.value;
if (selectedOption) { if (selectedOption) {
const [sortBy, order] = JSON.parse(selectedOption); const [sortBy, order] = JSON.parse(selectedOption);
if (sortBy === 'finance') {
this.dataStore.sortByFinance(order);
} else {
this.dataStore.sortBy(sortBy, order);
}
this.dataStore.sortBy(sortBy, order); this.dataStore.sortBy(sortBy, order);
} }

View File

@@ -10,287 +10,329 @@ let shouldUpdateFilters = true;
let modelFilter = []; let modelFilter = [];
let makeFilters; let makeFilters;
function sendReq() { function sendReq() {
var formData = { var formData = {
'action': 'handle_autocart_form', action: 'handle_autocart_form',
'minPrice': price.getValueStart(), minPrice: price.getValueStart(),
'maxPrice': price.getValue(), maxPrice: price.getValue(),
'minKilometres': kilometres.getValueStart(), minKilometres: kilometres.getValueStart(),
'maxKilometres': kilometres.getValue(), maxKilometres: kilometres.getValue(),
'minYear': year.getValueStart(), minYear: year.getValueStart(),
'maxYear': year.getValue(), maxYear: year.getValue(),
'autocart_nonce': jQuery('#autocart_nonce').val(), autocart_nonce: jQuery('#autocart_nonce').val(),
}; };
const vehiclesContainer = document.querySelector('.vehicles-container'); const vehiclesContainer = document.querySelector('.vehicles-container');
// vehiclesContainer.textContent = 'Loading...'; // vehiclesContainer.textContent = 'Loading...';
// Add skeleton cards to the vehicles container // Add skeleton cards to the vehicles container
for (let i = 0; i < 6; i++) { for (let i = 0; i < 6; i++) {
const skeletonCard = createSkeletonCard(); const skeletonCard = createSkeletonCard();
vehiclesContainer.appendChild(skeletonCard); vehiclesContainer.appendChild(skeletonCard);
} }
const filtersContainer = document.querySelector('.make-container'); const filtersContainer = document.querySelector('.make-container');
for (let i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
const skeletonListItem = createSkeletonListItem(); const skeletonListItem = createSkeletonListItem();
filtersContainer.appendChild(skeletonListItem); filtersContainer.appendChild(skeletonListItem);
} }
// Add skeleton list item to the filters container // Add skeleton list item to the filters container
// const skeletonListItem = createSkeletonListItem(); // const skeletonListItem = createSkeletonListItem();
// filtersContainer.appendChild(skeletonListItem); // filtersContainer.appendChild(skeletonListItem);
jQuery.ajax({ jQuery.ajax({
type: 'POST', type: 'POST',
url: ajax_object.ajax_url, url: ajax_object.ajax_url,
data: formData, data: formData,
success: function (response) { success: function (response) {
const vehicles = response.data.vehicles; const vehicles = response.data.vehicles;
if (dataStore) { if (dataStore) {
dataStore.unsubscribeAll(); dataStore.unsubscribeAll();
} }
// Initialize new data store
// Initialize new data store dataStore.vehicles = vehicles;
dataStore.vehicles = vehicles; filterManager = new FilterManager(dataStore);
filterManager = new FilterManager(dataStore); appliedFilters = new AppliedFilters(dataStore, filterManager);
appliedFilters = new AppliedFilters(dataStore, filterManager);
// filterManager = new FilterManager(dataStore); // filterManager = new FilterManager(dataStore);
// appliedFilters = new AppliedFilters(dataStore, filterManager); // appliedFilters = new AppliedFilters(dataStore, filterManager);
shouldUpdateFilters = true;
dataStore.subscribe(filteredVehicles => {
console.log('dataStore has been changed')
handleSuccess(filteredVehicles);
});
dataStore.notifySubscribers(vehicles); shouldUpdateFilters = true;
}, dataStore.subscribe((filteredVehicles) => {
error: function (xhr, status, error) { console.log('dataStore has been changed');
console.log(xhr.responseText); handleSuccess(filteredVehicles);
console.log('Status: ' + status); });
console.log('Error: ' + error);
jQuery("#inventory-search__search-button").text("Error"); dataStore.notifySubscribers(vehicles);
} },
}); error: function (xhr, status, error) {
console.log(xhr.responseText);
console.log('Status: ' + status);
console.log('Error: ' + error);
jQuery('#inventory-search__search-button').text('Error');
},
});
} }
function handleSuccess(vehicles, updateFilters = shouldUpdateFilters) { function handleSuccess(vehicles, updateFilters = shouldUpdateFilters) {
if(updateFilters){ if (updateFilters) {
createMakeList(vehicles); createMakeList(vehicles);
createBodyTypeList(vehicles); createBodyTypeList(vehicles);
createTransmissionList(vehicles); createTransmissionList(vehicles);
createExteriorList(vehicles); createExteriorList(vehicles);
} }
const vehiclesContainer = document.querySelector('.vehicles-container'); const vehiclesContainer = document.querySelector('.vehicles-container');
vehiclesContainer.innerHTML = ''; vehiclesContainer.innerHTML = '';
vehicles.forEach(vehicleData => {
const vehicle = new VehicleThumbnail(vehicleData);
// vehiclesContainer.appendChild(vehicle.generateCardHTML());
vehiclesContainer.appendChild(vehicle.generateCardElement());
}); vehicles.forEach((vehicleData) => {
const vehicle = new VehicleThumbnail(vehicleData);
// vehiclesContainer.appendChild(vehicle.generateCardHTML());
vehiclesContainer.appendChild(vehicle.generateCardElement());
});
} }
function createMakeList(vehicles){ function createMakeList(vehicles) {
const makeContainer = document.querySelector('.make-container');
makeContainer.innerHTML = '';
const makeContainer = document.querySelector('.make-container'); const makeCounts = vehicles.reduce((acc, vehicle) => {
makeContainer.innerHTML = ''; const { make } = vehicle;
acc[make] = (acc[make] || 0) + 1;
const makeCounts = vehicles.reduce((acc, vehicle) => { return acc;
const { make } = vehicle; }, {});
acc[make] = (acc[make] || 0) + 1; let makeValue = document.querySelector('#autocart-make-field').value;
return acc; // if(makeValue){
}, {}); // console.log('makeValue',makeValue);
let makeValue = document.querySelector('#autocart-make-field').value; // // dataStore.addFilter('make', makeValue);
// if(makeValue){ // }
// console.log('makeValue',makeValue); makeFilters = Object.entries(makeCounts).map(([make, count]) => {
// // dataStore.addFilter('make', makeValue); return filterManager.createMakeFilter(
// } {
makeFilters = Object.entries(makeCounts).map(([make, count]) => { text: make,
checked: makeValue.toLowerCase() === make.toLowerCase(),
return filterManager.createMakeFilter({ count,
text: make, models: fetchAvailableModels(vehicles, make),
checked: makeValue.toLowerCase() === make.toLowerCase(), },
count, dataStore
models: fetchAvailableModels(vehicles, make) );
}, dataStore); });
}); makeFilters.sort((a, b) => a.value.localeCompare(b.value));
makeFilters.forEach(make => { makeFilters.forEach((make) => {
makeContainer.appendChild(make.generateCardHTML());
makeContainer.appendChild(make.generateCardHTML()); make.subscribe((m) => initModelContainer(m));
make.subscribe(m=> initModelContainer(m)) });
});
} }
function createBodyTypeList(vehicles){ function createBodyTypeList(vehicles) {
const bodyTypeContainer = document.querySelector('.body-type-container'); const bodyTypeContainer = document.querySelector('.body-type-container');
bodyTypeContainer.innerHTML = ''; bodyTypeContainer.innerHTML = '';
const bodyType = vehicles.reduce((acc, vehicle) => { const bodyType = vehicles.reduce((acc, vehicle) => {
const { body_type } = vehicle; const { body_type } = vehicle;
acc[body_type] = (acc[body_type] || 0) + 1; acc[body_type] = (acc[body_type] || 0) + 1;
return acc; return acc;
}, {}); }, {});
filterManager.resetList('body_type'); filterManager.resetList('body_type');
bodyTypeFilters = Object.entries(bodyType).map(([body_type, count]) => filterManager.createBodyTypeFilter({ text: body_type, count}, dataStore)); bodyTypeFilters = Object.entries(bodyType).map(([body_type, count]) =>
bodyTypeFilters.forEach(body_type => { filterManager.createBodyTypeFilter({ text: body_type, count }, dataStore)
bodyTypeContainer.appendChild(body_type.initCheckbox()); );
// body_type.subscribe(m=> iniBodyTypeContainer(m)) bodyTypeFilters.sort((a, b) => a.value.localeCompare(b.value));
bodyTypeFilters.forEach((body_type) => {
bodyTypeContainer.appendChild(body_type.initCheckbox());
// body_type.subscribe(m=> iniBodyTypeContainer(m))
});
}
function createTransmissionList(vehicles) {
const transmissionContainer = document.querySelector(
'.transmission-container'
);
transmissionContainer.innerHTML = '';
const transmission = vehicles.reduce((acc, vehicle) => {
const { transmission_type } = vehicle;
acc[transmission_type] = (acc[transmission_type] || 0) + 1;
return acc;
}, {});
filterManager.resetList('transmission_type');
transmissionFilters = Object.entries(transmission).map(
([transmission_type, count]) =>
filterManager.createTransmissionFilter(
{ text: transmission_type, count },
dataStore
)
);
transmissionFilters.sort((a, b) => a.value.localeCompare(b.value));
transmissionFilters.forEach((transmission) => {
transmissionContainer.appendChild(transmission.initCheckbox());
});
}
function createExteriorList(vehicles) {
console.log(vehicles);
const exteriorContainer = document.querySelector('.exterior-color');
exteriorContainer.innerHTML = '';
const exterior = vehicles.reduce((acc, vehicle) => {
const { exterior_color } = vehicle;
acc[exterior_color] = (acc[exterior_color] || 0) + 1;
return acc;
}, {});
filterManager.resetList('exterior_color');
exteriorFilters = Object.entries(exterior).map(([exterior_color, count]) =>
filterManager.createExteriorFilter(
{ text: exterior_color, count },
dataStore
)
);
exteriorFilters.sort((a, b) => a.value.localeCompare(b.value));
exteriorFilters.forEach((exterior) => {
exteriorContainer.appendChild(exterior.initCheckbox());
});
}
function initModelContainer(make) {
let list = [
...new Set(
filterManager.makeFilters
.filter((m) => m.checked == true)
.map((m) => m.models)
.flat()
),
];
const modelContainer = document.querySelector('.model-container');
if (list.length === 0) {
modelContainer.innerHTML = '<p>Please Select a Make</p>';
} else if (list && list.length > 0) {
modelContainer.innerHTML = '';
list.sort((a, b) => a.value.localeCompare(b.value));
list.forEach((model) => {
modelContainer.appendChild(model.initCheckbox());
}); });
} else {
modelContainer.innerHTML = '<p>No models available</p>';
}
} }
function createTransmissionList(vehicles){ function initTrimContainer(model) {
const transmissionContainer = document.querySelector('.transmission-container'); let list = [
...new Set(
transmissionContainer.innerHTML = ''; filterManager.modelFilters
.filter((m) => m.checked == true)
.map((m) => m.trims)
.flat()
),
];
const transmission = vehicles.reduce((acc, vehicle) => { // const uniqueArray = [...new Set(array)];
const { transmission_type } = vehicle; const trimContainer = document.querySelector('.trim-container');
acc[transmission_type] = (acc[transmission_type] || 0) + 1;
return acc;
}, {});
filterManager.resetList('transmission_type'); if (list.length === 0) {
transmissionFilters = Object.entries(transmission).map(([transmission_type, count]) => filterManager.createTransmissionFilter({ text: transmission_type, count}, dataStore)); trimContainer.innerHTML = '<p>Please Select a Model</p>';
transmissionFilters.forEach(transmission => { } else if (list && list.length > 0) {
transmissionContainer.appendChild(transmission.initCheckbox()); trimContainer.innerHTML = '';
list.sort((a, b) => a.value.localeCompare(b.value));
list.forEach((trim) => {
trimContainer.appendChild(trim.initCheckbox());
}); });
} } else {
trimContainer.innerHTML = '<p>No trims available</p>';
function createExteriorList(vehicles){ }
console.log(vehicles);
const exteriorContainer = document.querySelector('.exterior-color');
exteriorContainer.innerHTML = '';
const exterior = vehicles.reduce((acc, vehicle) => {
const { exterior_color } = vehicle;
acc[exterior_color] = (acc[exterior_color] || 0) + 1;
return acc;
}, {});
filterManager.resetList('exterior_color');
exteriorFilters = Object.entries(exterior).map(([exterior_color, count]) => filterManager.createExteriorFilter({ text: exterior_color, count}, dataStore));
exteriorFilters.forEach(exterior => {
exteriorContainer.appendChild(exterior.initCheckbox());
});
}
function initModelContainer(make){
let list = [...new Set(filterManager.makeFilters.filter(m=>m.checked == true).map(m=>m.models).flat())];
const modelContainer = document.querySelector('.model-container');
if (list.length === 0) {
modelContainer.innerHTML = '<p>Please Select a Make</p>';
} else if (list && list.length > 0) {
modelContainer.innerHTML = '';
list.forEach(model => {
modelContainer.appendChild(model.initCheckbox());
});
} else {
modelContainer.innerHTML = '<p>No models available</p>';
}
}
function initTrimContainer(model){
let list = [...new Set(filterManager.modelFilters.filter(m=>m.checked == true).map(m=>m.trims).flat())];
// const uniqueArray = [...new Set(array)];
const trimContainer = document.querySelector('.trim-container');
if (list.length === 0) {
trimContainer.innerHTML = '<p>Please Select a Model</p>';
} else if (list && list.length > 0) {
trimContainer.innerHTML = '';
list.forEach(trim => {
trimContainer.appendChild(trim.initCheckbox());
});
} else {
trimContainer.innerHTML = '<p>No trims available</p>';
}
} }
function fetchAvailableModels(vehicles, make) { function fetchAvailableModels(vehicles, make) {
const filteredModels = vehicles const filteredModels = vehicles
.filter(vehicle => vehicle.make === make) .filter((vehicle) => vehicle.make === make)
.map(vehicle => vehicle.model); .map((vehicle) => vehicle.model);
// Count occurrences of each model // Count occurrences of each model
const modelCounts = filteredModels.reduce((acc, model) => { const modelCounts = filteredModels.reduce((acc, model) => {
acc[model] = (acc[model] || 0) + 1; acc[model] = (acc[model] || 0) + 1;
return acc; return acc;
}, {}); }, {});
// Convert to an array of objects // Convert to an array of objects
const modelsArray = Object.entries(modelCounts).map(([model, count]) => ({ model, count })); const modelsArray = Object.entries(modelCounts).map(([model, count]) => ({
modelsArray.map(m=>m['trims'] = fetchAvailableTrim(vehicles, m.model)) model,
return modelsArray; count,
}));
modelsArray.map((m) => (m['trims'] = fetchAvailableTrim(vehicles, m.model)));
return modelsArray;
} }
function fetchAvailableTrim(vehicles, modelName){ function fetchAvailableTrim(vehicles, modelName) {
const filteredVehicles = vehicles.filter(vehicle => vehicle.model === modelName); const filteredVehicles = vehicles.filter(
const trimCount = filteredVehicles.reduce((result, vehicle) => { (vehicle) => vehicle.model === modelName
vehicle.trim.forEach(trim => { );
const existingTrim = result.find(item => item.text === trim); const trimCount = filteredVehicles.reduce((result, vehicle) => {
if (existingTrim) { vehicle.trim.forEach((trim) => {
existingTrim.count += 1; const existingTrim = result.find((item) => item.text === trim);
} else { if (existingTrim) {
result.push({ text: trim, count: 1 }); existingTrim.count += 1;
} } else {
}); result.push({ text: trim, count: 1 });
return result; }
}, []); });
return trimCount; return result;
}, []);
return trimCount;
} }
function updateModel(models){ function updateModel(models) {
console.log('updateModel', models) console.log('updateModel', models);
} }
function debounce(func, delay) { function debounce(func, delay) {
let timeout; let timeout;
return function () { return function () {
const context = this; const context = this;
const args = arguments; const args = arguments;
clearTimeout(timeout); clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), delay); timeout = setTimeout(() => func.apply(context, args), delay);
}; };
} }
function updatePrice() { function updatePrice() {
const min = price.getValueStart(); const min = price.getValueStart();
const max = price.getValue(); const max = price.getValue();
const formattedMin = '$' + min.toLocaleString(); const formattedMin = '$' + min.toLocaleString();
const formattedMax = '$' + max.toLocaleString(); const formattedMax = '$' + max.toLocaleString();
document.getElementById('priceRange').textContent = `${formattedMin} to ${formattedMax}`; document.getElementById(
debouncedSendReq(); 'priceRange'
).textContent = `${formattedMin} to ${formattedMax}`;
debouncedSendReq();
} }
function updateYear() { function updateYear() {
const min = year.getValueStart(); const min = year.getValueStart();
const max = year.getValue(); const max = year.getValue();
document.getElementById('yearRange').textContent = `${min} to ${max}`; document.getElementById('yearRange').textContent = `${min} to ${max}`;
debouncedSendReq(); debouncedSendReq();
} }
function updateMileage() { function updateMileage() {
const min = kilometres.getValueStart(); const min = kilometres.getValueStart();
const max = kilometres.getValue(); const max = kilometres.getValue();
document.getElementById('KilometresRange').textContent = `${min} to ${max}`; document.getElementById('KilometresRange').textContent = `${min} to ${max}`;
debouncedSendReq(); debouncedSendReq();
} }
// Create debounced versions of sendReq // Create debounced versions of sendReq
const debouncedSendReq = debounce(sendReq, 300); const debouncedSendReq = debounce(sendReq, 300);
function createSkeletonCard() { function createSkeletonCard() {
const skeletonCard = document.createElement('div'); const skeletonCard = document.createElement('div');
skeletonCard.classList.add('bg-red-200', 'rounded-lg', 'shadow-md', 'animate-pulse'); skeletonCard.classList.add(
'bg-red-200',
const innerHTML = ` 'rounded-lg',
'shadow-md',
'animate-pulse'
);
const innerHTML = `
<div class="h-40 bg-red-300 rounded-t-lg"></div> <div class="h-40 bg-red-300 rounded-t-lg"></div>
<div class="p-4"> <div class="p-4">
<div class="h-12 bg-red-300 rounded-t-lg"></div> <div class="h-12 bg-red-300 rounded-t-lg"></div>
@@ -300,18 +342,23 @@ function createSkeletonCard() {
<div class="h-5 bg-red-300 rounded-b-lg"></div> <div class="h-5 bg-red-300 rounded-b-lg"></div>
</div> </div>
`; `;
skeletonCard.innerHTML = innerHTML;
return skeletonCard;
}
skeletonCard.innerHTML = innerHTML;
return skeletonCard;
}
function createSkeletonListItem() { function createSkeletonListItem() {
const listItem = document.createElement('li'); const listItem = document.createElement('li');
listItem.classList.add('w-full', 'bg-custom-red', 'rounded-lg', 'shadow-md', 'animate-pulse'); listItem.classList.add(
'w-full',
'bg-custom-red',
'rounded-lg',
'shadow-md',
'animate-pulse'
);
const innerHTML = ` const innerHTML = `
<div class="flex items-center justify-between p-1"> <div class="flex items-center justify-between p-1">
<div class="h-6 bg-custom-red-light w-2/3 rounded-lg"></div> <div class="h-6 bg-custom-red-light w-2/3 rounded-lg"></div>
@@ -319,7 +366,7 @@ function createSkeletonListItem() {
</div> </div>
`; `;
listItem.innerHTML = innerHTML; listItem.innerHTML = innerHTML;
return listItem; return listItem;
} }

View File

@@ -34,8 +34,8 @@ $response = get_transient("autocart_response");
<!-- Main Content --> <!-- Main Content -->
<div class="flex-grow flex max-w-7xl mx-auto"> <div class="flex-grow flex max-w-7xl mx-auto">
<!-- Left Drawer for Filters --> <!-- Left Drawer for Filters -->
<aside class="w-1/4 p-4 shadow-lg bg-white hidden md:block rounded"> <aside id="slide-out-filters" class="lg:w-1/4 md:w-1/4 w-10/12 lg:static md:static fixed p-4 shadow-lg bg-white lg:block md:block rounded overflow-y-auto transition duration-300 ease-in-out transform sm:transform-none sm:right-0 top-0 left-0 z-50 h-screen md:h-auto lg:h-auto">
<div class="mdc-select mdc-select--outlined .col-xl-3 rounded p-2 w-full" id="order-by"> <div class="mdc-select mdc-select--outlined col-xl-3 rounded pb-2 w-full" id="order-by">
<div class="mdc-select__anchor"> <div class="mdc-select__anchor">
<span class="mdc-notched-outline"> <span class="mdc-notched-outline">
<span class="mdc-notched-outline__leading"></span> <span class="mdc-notched-outline__leading"></span>
@@ -62,16 +62,13 @@ $response = get_transient("autocart_response");
</div> </div>
<div class="space-y-2"> <div class="space-y-2">
<!-- Panel 1 --> <!-- Panel 1 -->
<div class="border rounded p-2"> <div class="border rounded p-2" collapse-toggle>
<div class="flex justify-between items-center p-4"> <div class="flex justify-between items-center p-4 ac-accordion-header">
<div class="w-full text-left focus:outline-none transition"> Price </div> <div class="w-full text-left focus:outline-none transition"> Price </div>
<svg class="w-4 h-4 hover:bg-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24" <i class="fas fa-chevron-down hover:bg-gray-200"></i>
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7"></path>
</svg>
</div> </div>
<div class="mt-2"> <div class="mt-2 ac-accordion-content">
<div class="flex justify-center items-center"> <div class="flex justify-center items-center">
<span id="priceRange" class="slider-readings"> <?php echo '$' . number_format($minPrice) . ' to $' . number_format($maxPrice) ?> </span></div> <span id="priceRange" class="slider-readings"> <?php echo '$' . number_format($minPrice) . ' to $' . number_format($maxPrice) ?> </span></div>
<div class="mdc-slider mdc-slider--range" id="autocart-price-range-field"> <div class="mdc-slider mdc-slider--range" id="autocart-price-range-field">
@@ -94,16 +91,13 @@ $response = get_transient("autocart_response");
</div> </div>
</div> </div>
<!-- Panel 2 --> <!-- Panel 2 -->
<div class="border rounded p-2"> <div class="border rounded p-2" collapse-toggle>
<div class="flex justify-between items-center p-4"> <div class="flex justify-between items-center p-4 ac-accordion-header">
<div class="w-full text-left focus:outline-none transition"> Year </div> <div class="w-full text-left focus:outline-none transition"> Year </div>
<svg class="w-4 h-4 hover:bg-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24" <i class="fas fa-chevron-down hover:bg-gray-200"></i>
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7"></path>
</svg>
</div> </div>
<div class="mt-2"> <div class="mt-2 ac-accordion-content">
<div class="flex justify-center items-center"> <div class="flex justify-center items-center">
<span id="yearRange" class="slider-readings"> <?php echo $minYear .' to '.$maxYear; ?> </span> <span id="yearRange" class="slider-readings"> <?php echo $minYear .' to '.$maxYear; ?> </span>
</div> </div>
@@ -126,16 +120,13 @@ $response = get_transient("autocart_response");
</div> </div>
</div> </div>
<!-- Panel 3 --> <!-- Panel 3 -->
<div class="border rounded p-2"> <div class="border rounded p-2" collapse-toggle>
<div class="flex justify-between items-center p-4"> <div class="flex justify-between items-center p-4 ac-accordion-header">
<div class="w-full text-left focus:outline-none transition"> Kilometres </div> <div class="w-full text-left focus:outline-none transition"> Kilometres </div>
<svg class="w-4 h-4 hover:bg-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24" <i class="fas fa-chevron-down hover:bg-gray-200"></i>
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7"></path>
</svg>
</div> </div>
<div class="mt-2"> <div class="mt-2 ac-accordion-content">
<div class="flex justify-center items-center"> <div class="flex justify-center items-center">
<span id="KilometresRange" class="slider-readings">19000 to 222000 </span> <span id="KilometresRange" class="slider-readings">19000 to 222000 </span>
</div> </div>
@@ -159,95 +150,77 @@ $response = get_transient("autocart_response");
</div> </div>
<!-- Panel 4 --> <!-- Panel 4 -->
<div class="border rounded p-2"> <div class="border rounded p-2" collapse-toggle>
<div class="flex justify-between items-center p-4"> <div class="flex justify-between items-center p-4 ac-accordion-header">
<div class="w-full text-left focus:outline-none transition"> Make </div> <div class="w-full text-left focus:outline-none transition"> Make </div>
<svg class="w-4 h-4 hover:bg-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24" <i class="fas fa-chevron-down hover:bg-gray-200"></i>
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7"></path>
</svg>
</div> </div>
<div class="mt-2"> <div class="mt-2 ac-accordion-content">
<ul class="make-container list-none text-gray-900 w-48 bg-white text-sm font-medium rounded-lg w-full"> <ul class="make-container list-none text-gray-900 w-48 bg-white text-sm font-medium rounded-lg w-full">
</ul> </ul>
</div> </div>
</div> </div>
<div class="border rounded p-2"> <div class="border rounded p-2" collapse-toggle>
<div class="flex justify-between items-center p-4"> <div class="flex justify-between items-center p-4 ac-accordion-header" id="model-collapse-toggle ">
<div class="w-full text-left focus:outline-none transition"> Model </div> <div class="w-full text-left focus:outline-none transition"> Model </div>
<svg class="w-4 h-4 hover:bg-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24" <i class="fas fa-chevron-down hover:bg-gray-200"></i>
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7"></path>
</svg>
</div> </div>
<div class="mt-2"> <div class="mt-2 ac-accordion-content">
<ul class="model-container list-none text-gray-900 w-48 bg-white text-sm font-medium rounded-lg w-full"> <ul class="model-container list-none text-gray-900 w-48 bg-white text-sm font-medium rounded-lg w-full ">
<p>Please Select a Make.</p> <p>Please Select a Make.</p>
</ul> </ul>
</div> </div>
</div> </div>
<div class="border rounded p-2"> <div class="border rounded p-2" collapse-toggle>
<div class="flex justify-between items-center p-4"> <div class="flex justify-between items-center p-4 ac-accordion-header">
<div class="w-full text-left focus:outline-none transition"> Trim </div> <div class="w-full text-left focus:outline-none transition"> Trim </div>
<svg class="w-4 h-4 hover:bg-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24" <i class="fas fa-chevron-down hover:bg-gray-200"></i>
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7"></path>
</svg>
</div> </div>
<div class="mt-2"> <div class="mt-2 ac-accordion-content">
<ul class="trim-container list-none text-gray-900 bg-white text-sm font-medium rounded-lg w-full"> <ul class="trim-container list-none text-gray-900 bg-white text-sm font-medium rounded-lg w-full">
<p>Please Select a Model.</p> <p>Please Select a Model.</p>
</ul> </ul>
</div> </div>
</div> </div>
<div class="border rounded p-2"> <div class="border rounded p-2" collapse-toggle>
<div class="flex justify-between items-center p-4"> <div class="flex justify-between items-center p-4 ac-accordion-header">
<div class="w-full text-left focus:outline-none transition"> Body Style </div> <div class="w-full text-left focus:outline-none transition"> Body Style </div>
<svg class="w-4 h-4 hover:bg-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24" <i class="fas fa-chevron-down hover:bg-gray-200"></i>
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7"></path>
</svg>
</div> </div>
<div class="mt-2"> <div class="mt-2 ac-accordion-content">
<ul class="body-type-container list-none text-gray-900 bg-white text-sm font-medium rounded-lg w-full"> <ul class="body-type-container list-none text-gray-900 bg-white text-sm font-medium rounded-lg w-full">
</ul> </ul>
</div> </div>
</div> </div>
<div class="border rounded p-2"> <div class="border rounded p-2" collapse-toggle>
<div class="flex justify-between items-center p-4"> <div class="flex justify-between items-center p-4 ac-accordion-header">
<div class="w-full text-left focus:outline-none transition"> Transmission </div> <div class="w-full text-left focus:outline-none transition"> Transmission </div>
<svg class="w-4 h-4 hover:bg-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24" <i class="fas fa-chevron-down hover:bg-gray-200"></i>
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7"></path>
</svg>
</div> </div>
<div class="mt-2"> <div class="mt-2 ac-accordion-content">
<ul class="transmission-container list-none text-gray-900 bg-white text-sm font-medium rounded-lg w-full"> <ul class="transmission-container list-none text-gray-900 bg-white text-sm font-medium rounded-lg w-full">
</ul> </ul>
</div> </div>
</div> </div>
<div class="border rounded p-2"> <div class="border rounded p-2" collapse-toggle>
<div class="flex justify-between items-center p-4"> <div class="flex justify-between items-center p-4 ac-accordion-header">
<div class="w-full text-left focus:outline-none transition"> Exterior Color </div> <div class="w-full text-left focus:outline-none transition"> Exterior Color </div>
<svg class="w-4 h-4 hover:bg-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24" <i class="fas fa-chevron-down hover:bg-gray-200"></i>
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7"></path>
</svg>
</div> </div>
<div class="mt-2"> <div class="mt-2 ac-accordion-content">
<ul class="exterior-color list-none text-gray-900 bg-white text-sm font-medium rounded-lg w-full"> <ul class="exterior-color list-none text-gray-900 bg-white text-sm font-medium rounded-lg w-full">
</ul> </ul>
@@ -259,11 +232,15 @@ $response = get_transient("autocart_response");
<!-- Main Content --> <!-- Main Content -->
<div class="w-3/4 ml-1/4 p-4 pb-0 flex-grow"> <div class="w-3/4 ml-1/4 p-4 pb-0 flex-grow">
<!-- Top App Bar with Menu Button --> <!-- Top App Bar with Menu Button -->
<header class="shadow-lg bg-white p-4 flex justify-between items-center rounded"> <header class="shadow-lg bg-white p-4 flex justify-between items-center rounded" >
<div class="mt-2" id="applied-filters-block"></div> <div class="mt-2" id="applied-filters-block"></div>
<div class="flex items-center space-x-4"> <div class="flex items-center space-x-4">
<i id="grid-view" class="fas fa-th text-gray-500 cursor-pointer transition duration-300 transform hover:scale-110 hover:shadow-md ripple selected"></i> <i id="grid-view" class="fas fa-th text-gray-500 cursor-pointer transition duration-300 transform hover:scale-110 hover:shadow-md ripple selected"></i>
<i id="list-view" class="fas fa-list text-gray-500 cursor-pointer transition duration-300 transform hover:scale-110 hover:shadow-md ripple"></i> <i id="list-view" class="fas fa-list text-gray-500 cursor-pointer transition duration-300 transform hover:scale-110 hover:shadow-md ripple"></i>
<label for="open-menu" tabindex="0" aria-haspopup="true" role="button" aria-controls="menu" class="fixed bottom-4 right-4 cursor-pointer m-0 md:hidden lg:hidden" id="openmenu">
<i id="filter-toggle" class="fas fa-sliders-h text-gray-500 cursor-pointer transition duration-300 transform hover:scale-110"></i>
</label>
<input type="checkbox" data-menu id="open-menu" class="peer hidden">
</div> </div>
</header> </header>
@@ -283,18 +260,57 @@ if ($make) {
<script> <script>
const filtersDrawerCheckbox = document.getElementById('open-menu');
const filtersDrawer = document.querySelector('#slide-out-filters');
const filterToggle = document.querySelector('#filter-toggle');
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
price = new mdc.slider.MDCSlider(document.querySelector('#autocart-price-range-field')); price = new mdc.slider.MDCSlider(document.querySelector('#autocart-price-range-field'));
year = new mdc.slider.MDCSlider(document.querySelector('#autocart-year-range-field')); year = new mdc.slider.MDCSlider(document.querySelector('#autocart-year-range-field'));
kilometres = new mdc.slider.MDCSlider(document.querySelector('#autocart-kilometres-range-field')); kilometres = new mdc.slider.MDCSlider(document.querySelector('#autocart-kilometres-range-field'));
price.listen('MDCSlider:input', updatePrice); price.listen('MDCSlider:input', updatePrice);
year.listen('MDCSlider:input', updateYear); year.listen('MDCSlider:input', updateYear);
kilometres.listen('MDCSlider:input', updateMileage); kilometres.listen('MDCSlider:input', updateMileage);
new DisplayMode(); new DisplayMode();
dataStore = new DataStore([]); dataStore = new DataStore([]);
new SortBy(dataStore); new SortBy(dataStore);
sendReq(); sendReq();
const accordionItems = document.querySelectorAll("[collapse-toggle]");
accordionItems.forEach(item => {
const header = item.querySelector(".ac-accordion-header");
const content = item.querySelector(".ac-accordion-content");
const icon = header.querySelector("i.fas");
header.addEventListener("click", function() {
item.classList.toggle("collapsed");
// content.classList.toggle('hidden');
icon.classList.toggle('fa-chevron-down');
icon.classList.toggle('fa-chevron-up');
// content.style.display = content.style.display === "none" ? "block" : "none";
});
});
}); });
filtersDrawerCheckbox.addEventListener('change', function() {
if (this.checked) {
filtersDrawer.style.translate = 0;
filterToggle.classList.add('selected')
} else {
// filtersDrawer.classList.add('hidden'); // Close the drawer
filterToggle.classList.remove('selected')
filtersDrawer.style.translate = "-100%";
}
});
</script> </script>

View File

@@ -193,9 +193,12 @@ $carMakes = [
<?php wp_nonce_field('autocart_nonce', 'autocart_nonce'); ?> <?php wp_nonce_field('autocart_nonce', 'autocart_nonce'); ?>
<div class="lg:col-span-2"> <div class="col-span-2">
<button type="submit" aria-label="Find Your Vehicle Search" class="w-full bg-red-500 hover:bg-red-800 transition-colors duration-300 text-white font-medium py-2 px-4 rounded" id="inventory-search-button"> <button type="submit" aria-label="Find Your Vehicle Search" class="w-full bg-red-500 hover:bg-red-800 transition-colors duration-300 text-white font-medium py-2 px-4 flex flex-row flex-wrap content-around justify-center items-center rounded" id="inventory-search-button">
<i class="bi-search mr-2"></i>Search <i class="bi-search mr-2"></i>
<span id="button-content">Search </span>
<span class="btn-ring hidden"></span>
</button> </button>
</div> </div>
</div> </div>
@@ -330,6 +333,7 @@ $carMakes = [
// const price = document.querySelector('#autocart-price-field'); // const price = document.querySelector('#autocart-price-field');
const year = document.querySelector('#vehicle_search_year'); const year = document.querySelector('#vehicle_search_year');
const make = document.querySelector('#vehicle_search_make'); const make = document.querySelector('#vehicle_search_make');
const loading = document.querySelector('.btn-ring');
// let priceRange = JSON.parse(priceWidget.value); // let priceRange = JSON.parse(priceWidget.value);
// let minPrice = priceRange[0]; // let minPrice = priceRange[0];
@@ -367,32 +371,37 @@ $carMakes = [
'make': make.value, 'make': make.value,
'autocart_nonce': jQuery('#autocart_nonce').val(), 'autocart_nonce': jQuery('#autocart_nonce').val(),
}; };
jQuery("#inventory-search-button").text("Loading..."); jQuery(" #button-content").text("Loading...");
loading.classList.remove('hidden');
jQuery.ajax({ jQuery.ajax({
type: 'POST', type: 'POST',
url: ajax_object.ajax_url, url: ajax_object.ajax_url,
data: formData, data: formData,
success: function(response) { success: function(response) {
if(response.success){ loading.classList.add('hidden'); // Hide the btn-ring on success
if (response.success) {
const vehicles = response.data.vehicles; const vehicles = response.data.vehicles;
if (inputs) { if (inputs) {
inputs.forEach(element => { inputs.forEach(element => {
createOptions(vehicles, element); createOptions(vehicles, element);
}); });
} }
jQuery("#inventory-search-button").text("Search (" + vehicles.length + ")"); jQuery(" #button-content").text("Search (" + vehicles.length + ")");
}else{ } else {
alert(response.data.message); alert(response.data.message);
jQuery("#inventory-search-button").text("Search"); jQuery(" #button-content").text("Search");
} }
}, },
error: function(xhr, status, error) { error: function(xhr, status, error) {
loading.classList.add('hidden'); // Hide the btn-ring on error
console.log(xhr.responseText); console.log(xhr.responseText);
console.log('Status: ' + status); console.log('Status: ' + status);
console.log('Error: ' + error); console.log('Error: ' + error);
jQuery("#inventory-search-button").text("Error"); // jQuery("").text("Error");
} }
}); });
} }

View File

@@ -173,8 +173,8 @@ $image_title = !empty($vehicle_images[0]['title']) ? $vehicle_images[0]['title']
$image_description = !empty($vehicle_images[0]['description']) ? $vehicle_images[0]['description'] : ''; $image_description = !empty($vehicle_images[0]['description']) ? $vehicle_images[0]['description'] : '';
?> ?>
<div class="max-w-7xl mx-auto"> <div class="max-w-7xl mx-auto grid">
<div class="grid grid-cols-2"> <div class="grid grid-cols-2 hidden lg:grid">
<div class="relative group cursor-pointer"> <div class="relative group cursor-pointer">
<img src="<?php echo $vehicle_images[0]['url']; ?>" alt="<?php echo $image_title; ?>" class="w-full h-full object-cover"> <img src="<?php echo $vehicle_images[0]['url']; ?>" alt="<?php echo $image_title; ?>" class="w-full h-full object-cover">
@@ -211,12 +211,12 @@ $image_description = !empty($vehicle_images[0]['description']) ? $vehicle_images
</div> </div>
<div class="bg-gray-100 dark:bg-gray-800 py-4"> <div class="bg-gray-100 dark:bg-gray-800 py-4 grid">
<!-- Single Car Information --> <!-- Single Car Information -->
<div class="lg:grid grid-cols-3 relative"> <div class="lg:grid lg:grid-cols-3 grid grid-cols-1 relative">
<!-- Vehicle Details --> <!-- Vehicle Details -->
<div class="mx-auto col-span-2"> <div class="lg:mx-auto md:mx-auto col-span-2">
<!-- Single Car --> <!-- Single Car -->
<div class="m-4"> <div class="m-4">
@@ -319,18 +319,31 @@ $image_description = !empty($vehicle_images[0]['description']) ? $vehicle_images
<p class="mb-4 font-bold text-gray-700 dark:text-gray-300">Options</p> <p class="mb-4 font-bold text-gray-700 dark:text-gray-300">Options</p>
<div id="accordion-flush" data-accordion="collapse" data-active-classes="bg-white dark:bg-gray-900 text-gray-900 dark:text-white mt-4 transition-all duration-300" data-inactive-classes="text-gray-500 dark:text-gray-400"> <div id="accordion-flush" data-accordion="collapse" data-active-classes="bg-white dark:bg-gray-900 text-gray-900 dark:text-white mt-4 transition-all duration-300" data-inactive-classes="text-gray-500 dark:text-gray-400">
<div class="md:grid grid-cols-3"> <div class="md:grid grid-cols-3">
<ul class="col-span-1 flex-column space-y-4 text-sm font-medium text-gray-500 dark:text-gray-400 md:me-4 mb-4 md:mb-0"> <div class="lg:col-span-1 sm:flex-rows flex-row md:block flex md:col-span-1 lg:flex-column md:flex-column text-sm font-medium text-gray-500 dark:text-gray-400 w-full gap-4">
<?php foreach ($groupedFeatures as $category => $features) : ?> <button id="tabs-left" class="md:hidden lg:hidden inline-flex items-center justify-center px-2 py-2 text-gray-400 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-300 disabled:opacity-50 rounded-lg md:me-4 mb-4">
<?php <i class="fas fa-angle-left"></i>
// Remove special characters and spaces from category for use in HTML IDs </button>
$categorySlug = strtolower(preg_replace('/[^a-z0-9]/', '', $category)); <ul id="tabs-container" class="lg:col-span-1 sm:flex-rows flex-row md:block flex overflow-scroll md:col-span-1 lg:flex-column md:flex-column lg:space-y-4 md:space-y-4 text-sm font-medium text-gray-500 dark:text-gray-400 md:me-4 mb-4 md:mb-0 w-full overflow-scroll md:me-4 mb-4 gap-4">
?>
<button class="inline-flex items-center text-left px-4 py-3 rounded-lg hover:text-gray-900 bg-gray-50 hover:bg-gray-300 w-full dark:hover:bg-gray-700 dark:hover:text-white text-gray-900 border border-gray-200 dark:bg-gray-700 dark:border-gray-600 dark:text-white transition-all duration-300 ripple-effect" data-tab-target="#tab-<?= $categorySlug ?>-body-1" data-te-ripple-init>
<?= $category ?> <?php foreach ($groupedFeatures as $category => $features) : ?>
</button> <?php
<?php endforeach; ?> // Remove special characters and spaces from category for use in HTML IDs
</ul> $categorySlug = strtolower(preg_replace('/[^a-z0-9]/', '', $category));
<div class="sticky-container col-span-2 p-6 bg-gray-50 text-medium text-gray-900 border border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white transition-all duration-300 top-32 lg:top-56" id="tabs-viewer"> ?>
<button class="inline-flex items-center text-left lg:text-left md:text-left sm:text-center px-4 py-3 rounded-lg hover:text-gray-900 bg-gray-50 hover:bg-gray-300 w-full dark:hover:bg-gray-700 dark:hover:text-white text-gray-900 border border-gray-200 dark:bg-gray-700 dark:border-gray-600 dark:text-white transition-all duration-300 md:ripple-effect lg:ripple-effect" data-tab-target="#tab-<?= $categorySlug ?>-body-1" data-te-ripple-init>
<?= $category ?>
</button>
<?php endforeach; ?>
</ul>
<button id="tabs-right" class="md:hidden lg:hidden inline-flex items-center justify-center px-2 py-2 text-gray-400 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-300 disabled:opacity-50 rounded-lg md:me-4 mb-4">
<i class="fas fa-angle-right"></i>
</button>
</div>
<div class="sticky-container col-span-2 p-6 bg-gray-50 text-medium text-gray-900 border border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white transition-all duration-300 top-32 lg:top-56 lg:ml-4 md:ml-4" id="tabs-viewer">
</div> </div>
@@ -357,8 +370,8 @@ $image_description = !empty($vehicle_images[0]['description']) ? $vehicle_images
</div> </div>
<!-- Vehicle Financing and Booking Widget --> <!-- Vehicle Financing and Booking Widget -->
<div class="px-4 col-span-1 relative"> <div class="px-4 col-span-1 relative order-first md:order-last">
<div class="sticky-container grid gap-3 top-56"> <div class="sticky-container grid gap-3 top-56">
<button role="button" class="prev px-2 py-2 rounded-full bg-neutral-100 text-neutral-900 group absolute top-1/4 left-4 transform -translate-y-1/2 z-10" aria-label="prev" onclick="navigateSlider(-1)"> <button role="button" class="prev px-2 py-2 rounded-full bg-neutral-100 text-neutral-900 group absolute top-1/4 left-4 transform -translate-y-1/2 z-10" aria-label="prev" onclick="navigateSlider(-1)">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 group-active:-translate-x-2 transition-all duration-200 ease-linear"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 group-active:-translate-x-2 transition-all duration-200 ease-linear">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" /> <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
@@ -568,7 +581,7 @@ const mergedDetails = {
selector: 'glightbox', selector: 'glightbox',
touchNavigation: true, touchNavigation: true,
loop: true, loop: true,
startAt: selectedSlide, // Set the starting slide startAt: selectedSlide,
onClose: function() { onClose: function() {
const slideElements = document.querySelectorAll('#thumbnailContainer .thumbnail'); const slideElements = document.querySelectorAll('#thumbnailContainer .thumbnail');
if (slideElements.length >= lightbox.index) { if (slideElements.length >= lightbox.index) {
@@ -609,6 +622,18 @@ const mergedDetails = {
} }
jQuery(document).ready(function() { jQuery(document).ready(function() {
const tabsLeftButton = document.getElementById('tabs-left');
const tabsRightButton = document.getElementById('tabs-right');
tabsLeftButton.addEventListener('click', function () {
scrollTabs(-1);
});
tabsRightButton.addEventListener('click', function () {
scrollTabs(1);
});
var queryString = window.location.search; var queryString = window.location.search;
var urlParams = new URLSearchParams(queryString); var urlParams = new URLSearchParams(queryString);
@@ -663,7 +688,6 @@ const mergedDetails = {
function rippleEffect(event) { function rippleEffect(event) {
const btn = event.currentTarget; const btn = event.currentTarget;
// Add classes to the selected element
btn.classList.add("overflow-hidden", "shadow", "relative"); btn.classList.add("overflow-hidden", "shadow", "relative");
const circle = document.createElement("span"); const circle = document.createElement("span");
@@ -703,9 +727,8 @@ const mergedDetails = {
function scrollCarouselRight() { function scrollCarouselRight() {
const carousel = document.querySelector('.overflow-x-scroll'); const carousel = document.querySelector('.overflow-x-scroll');
const maxScrollRight = carousel.scrollWidth - carousel.offsetWidth; // Calculate max scrollable distance const maxScrollRight = carousel.scrollWidth - carousel.offsetWidth;
// Prevent scrolling beyond the end
if (carousel.scrollLeft >= maxScrollRight) { if (carousel.scrollLeft >= maxScrollRight) {
return; return;
} }
@@ -715,4 +738,38 @@ const mergedDetails = {
behavior: 'smooth' behavior: 'smooth'
}); });
} }
function scrollTabs(direction) {
const tabsContainer = document.getElementById('tabs-container');
const tabs = tabsContainer.querySelectorAll('button');
let totalWidth = 0;
tabs.forEach(tab => {
console.log(tab.offsetWidth);
if (isElementVisible(tab)) {
totalWidth += tab.offsetWidth;
}
});
const scrollAmount = direction * totalWidth;
tabsContainer.scrollBy({
left: scrollAmount,
behavior: 'smooth'
});
}
function isElementVisible(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
</script> </script>

View File

@@ -36,6 +36,7 @@ function themeStarter_setup()
array( array(
'primary' => __('Primary Menu', 'themeStarter'), 'primary' => __('Primary Menu', 'themeStarter'),
'secondary' => __('Secondary Menu', 'themeStarter'), 'secondary' => __('Secondary Menu', 'themeStarter'),
'mobile' => __('Mobile Menu', 'themeStarter'),
) )
); );
@@ -82,4 +83,3 @@ function themeStarter_setup()
add_theme_support('wc-product-gallery-lightbox'); add_theme_support('wc-product-gallery-lightbox');
add_theme_support('wc-product-gallery-slider'); add_theme_support('wc-product-gallery-slider');
} }

View File

@@ -2060,6 +2060,21 @@ html {
background-color: rgb(87 83 78 / var(--tw-bg-opacity)); background-color: rgb(87 83 78 / var(--tw-bg-opacity));
} }
.hover\:bg-stone-100:hover {
--tw-bg-opacity: 1;
background-color: rgb(245 245 244 / var(--tw-bg-opacity));
}
.hover\:bg-stone-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(231 229 228 / var(--tw-bg-opacity));
}
.hover\:bg-stone-300:hover {
--tw-bg-opacity: 1;
background-color: rgb(214 211 209 / var(--tw-bg-opacity));
}
.hover\:text-white:hover { .hover\:text-white:hover {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity)); color: rgb(255 255 255 / var(--tw-text-opacity));

View File

@@ -6,7 +6,6 @@
* @package ThemeStarter * @package ThemeStarter
*/ */
require_once(get_theme_file_path('/includes/back-end/helper_functions.php'));
?> ?>
@@ -16,11 +15,8 @@ require_once(get_theme_file_path('/includes/back-end/helper_functions.php'));
<!-- Header --> <!-- Header -->
<nav id="header-nav" class="fixed w-full top-0 z-50"> <nav id="header-nav" class="fixed w-full top-0 z-50">
<section class="relative"> <section class="relative">
<!-- Top Banner --> <!-- Top Banner -->
<div class="bg-stone-800 px-4"> <div class="bg-stone-800 px-4">
<div class="max-w-7xl mx-auto py-4"> <div class="max-w-7xl mx-auto py-4">
@@ -69,10 +65,6 @@ require_once(get_theme_file_path('/includes/back-end/helper_functions.php'));
<!-- Core Nav --> <!-- Core Nav -->
<div class="relative px-4 py-2 bg-white backdrop-blur-lg w-full shadow-md"> <div class="relative px-4 py-2 bg-white backdrop-blur-lg w-full shadow-md">
<!-- <div class="absolute top-0 left-0 inset-0 flex w-full">
<?php /** get_search_form(); */ ?>
</div> -->
<div class="relative z-10 flex justify-between max-w-7xl mx-auto"> <div class="relative z-10 flex justify-between max-w-7xl mx-auto">
<!-- Header Logo --> <!-- Header Logo -->
<a class="relative z-50 flex items-center space-x-4" href="<?php echo get_site_url(); ?>"> <a class="relative z-50 flex items-center space-x-4" href="<?php echo get_site_url(); ?>">
@@ -94,11 +86,6 @@ require_once(get_theme_file_path('/includes/back-end/helper_functions.php'));
get_template_part('template-parts/partials/apply-for-financing-button'); get_template_part('template-parts/partials/apply-for-financing-button');
?> ?>
</div> </div>
<!-- <div class="flex relative">
<button aria-label="Search Toggle" id="toggle-search">
<i class="bi bi-search"></i>
</button>
</div> -->
<div class="flex relative"> <div class="flex relative">
<button aria-label="Mobile Menu Toggle" id="toggle-nav" class="toggle-menu"> <button aria-label="Mobile Menu Toggle" id="toggle-nav" class="toggle-menu">
<i></i> <i></i> <i></i> <i></i>
@@ -140,57 +127,8 @@ require_once(get_theme_file_path('/includes/back-end/helper_functions.php'));
<div class="mx-auto mb-4 w-11/12 h-1 border-t border-stone-400"></div> <div class="mx-auto mb-4 w-11/12 h-1 border-t border-stone-400"></div>
<ul role="list" class="space-y-2"> <?php get_template_part('template-parts/partials/menu-accordion-loop')
<!-- Menu Loop --> ?>
<?php $pages = get_pages_as_array();
foreach ($pages as $page) {
$pageID = $page['page']->ID;
$pageTitle = $page['page']->post_title;
$pageSlug = $page['page']->post_name;
$pageBG =
$page['page']->post_name . '.png';
$pageBootstrapIcon =
get_field('bootstrap_icon', $page['page']->ID); ?>
<li class="accordion">
<div class="flex px-2 hover:bg-stone-500 hover:text-white rounded-md justify-between">
<a href="<?php echo get_site_url() . '/' . $pageSlug; ?>" class="gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold flex items-center align-middle">
<i class="<?php echo $pageBootstrapIcon ?> text-2xl" aria-hidden="true"></i>
<p><?php echo $pageTitle ?></p>
</a>
<?php if ($page['subpages']) { ?>
<button aria-label="Accordion Dropdown Toggle" class="accordion-toggle">
<i class="fas fa-chevron-down items-center ml-auto rounded-md px-2.5 py-2" aria-hidden="true"></i>
<i class="fas fa-times items-center ml-auto rounded-md px-3 py-2" aria-hidden="true"></i>
</button>
<?php } ?>
</div>
<ul class="accordion-content space-y-2">
<?php foreach ($page['subpages'] as $subpage) {
$subpageID =
$subpage->ID;
$subpageTitle = $subpage->post_title;
$subpageSlug =
$subpage->post_name;
$subpageBG = $subpage->post_name . '.png';
$subpageBootstrapIcon = get_field('bootstrap_icon', $subpage->ID);
?>
<li class="p-2">
<a href="<?php echo get_site_url() . '/' . $pageSlug . '/' . $subpageSlug ?>" class="flex space-x-2 items-center"><i class="bi-caret-right-fill"></i>
<p><?php echo $subpageTitle ?></p>
</a>
</li>
<?php } ?>
</ul>
</li>
<!-- Horizontal Rule -->
<!-- <div class="horizontal-rule w-4/5 mt-4 mx-auto bg-gray-800"></div> -->
<?php } ?>
</ul>
</div> </div>

View File

@@ -0,0 +1,80 @@
<?php
/**
* Menu Accordion template.
*
* @package ThemeStarter
*/
?>
<ul role="list" class="space-y-2">
<?php
// Get the menu items
$main_menu_items = wp_get_nav_menu_items('mobile-menu');
// Initialize an empty array to store the menu structure
$menu_structure = array();
// Iterate through each menu item to build the menu structure
foreach ($main_menu_items as $menu_item) {
// If the menu item has no parent, add it as a root level item
if ($menu_item->menu_item_parent == 0) {
$menu_structure[$menu_item->ID] = array(
'title' => $menu_item->title,
'url' => $menu_item->url,
'children' => array()
);
} else {
// If the menu item has a parent, add it as a child of its parent
$parent_id = $menu_item->menu_item_parent;
$menu_structure[$parent_id]['children'][] = array(
'title' => $menu_item->title,
'url' => $menu_item->url
);
}
}
// Loop through menu items with no parents (parents are the "parent" items)
foreach ($menu_structure as $menu_item_id => $menu_item_data) {
$menuItemTitle = $menu_item_data['title'];
$menuItemSlug = $menu_item_data['url'];
?>
<li class="accordion">
<div class="flex px-2 hover:bg-stone-500 hover:text-white rounded-md justify-between">
<a href="<?php echo $menuItemSlug; ?>" class="gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold flex items-center align-middle">
<p><?php echo $menuItemTitle ?></p>
</a>
<?php if (!empty($menu_item_data['children'])) { ?>
<button aria-label="Accordion Dropdown Toggle" class="accordion-toggle">
<i class="fas fa-chevron-down items-center ml-auto rounded-md px-2.5 py-2" aria-hidden="true"></i>
<i class="fas fa-times items-center ml-auto rounded-md px-3 py-2" aria-hidden="true"></i>
</button>
<?php } ?>
</div>
<?php
// Check if there are children for this menu item
if (!empty($menu_item_data['children'])) {
?>
<ul class="accordion-content space-y-2">
<?php
// Loop through children
foreach ($menu_item_data['children'] as $child) {
$childTitle = $child['title'];
$childUrl = $child['url'];
?>
<li class="hover:bg-stone-300 rounded-md">
<a class="inset-0 flex px-4 py-2" href="<?php echo $childUrl ?>"><?php echo $childTitle ?></a>
</li>
<?php
}
?>
</ul>
<?php
}
?>
</li>
<?php
}
?>
</ul>

View File

@@ -0,0 +1,66 @@
<?php
/**
* Pages Accordion template.
*
* @package ThemeStarter
*/
require_once(get_theme_file_path('/includes/back-end/helper_functions.php'));
?>
<!-- Accordion Menu Loop -->
<ul role="list" class="space-y-2">
<!-- Menu Loop -->
<?php $pages = get_pages_as_array();
foreach ($pages as $page) {
$pageID = $page['page']->ID;
$pageTitle = $page['page']->post_title;
$pageSlug = $page['page']->post_name;
$pageBG =
$page['page']->post_name . '.png';
$pageBootstrapIcon =
get_field('bootstrap_icon', $page['page']->ID); ?>
<li class="accordion">
<div class="flex px-2 hover:bg-stone-500 hover:text-white rounded-md justify-between">
<a href="<?php echo get_site_url() . '/' . $pageSlug; ?>" class="gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold flex items-center align-middle">
<i class="<?php echo $pageBootstrapIcon ?> text-2xl" aria-hidden="true"></i>
<p><?php echo $pageTitle ?></p>
</a>
<?php if ($page['subpages']) { ?>
<button aria-label="Accordion Dropdown Toggle" class="accordion-toggle">
<i class="fas fa-chevron-down items-center ml-auto rounded-md px-2.5 py-2" aria-hidden="true"></i>
<i class="fas fa-times items-center ml-auto rounded-md px-3 py-2" aria-hidden="true"></i>
</button>
<?php } ?>
</div>
<ul class="accordion-content space-y-2">
<?php foreach ($page['subpages'] as $subpage) {
$subpageID =
$subpage->ID;
$subpageTitle = $subpage->post_title;
$subpageSlug =
$subpage->post_name;
$subpageBG = $subpage->post_name . '.png';
$subpageBootstrapIcon = get_field('bootstrap_icon', $subpage->ID);
?>
<li class="p-2">
<a href="<?php echo get_site_url() . '/' . $pageSlug . '/' . $subpageSlug ?>" class="flex space-x-2 items-center"><i class="bi-caret-right-fill"></i>
<p><?php echo $subpageTitle ?></p>
</a>
</li>
<?php } ?>
</ul>
</li>
<!-- Horizontal Rule -->
<!-- <div class="horizontal-rule w-4/5 mt-4 mx-auto bg-gray-800"></div> -->
<?php } ?>
</ul>