mirror of
https://github.com/qdrant/landing_page.git
synced 2026-10-06 03:18:30 +02:00
add filters and sorting to url params on the customers page (#2456)
This commit is contained in:
@@ -6,8 +6,84 @@ const FILTER_KEYS = [
|
|||||||
"use_cases"
|
"use_cases"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const SORT_PARAM = "sort";
|
||||||
|
|
||||||
|
const VALID_SORT_VALUES = new Set([
|
||||||
|
"name-asc",
|
||||||
|
"name-desc",
|
||||||
|
"industry-asc",
|
||||||
|
"product-asc",
|
||||||
|
"company_size-asc",
|
||||||
|
"location-asc"
|
||||||
|
]);
|
||||||
|
|
||||||
const DESKTOP_MIN_WIDTH = 992;
|
const DESKTOP_MIN_WIDTH = 992;
|
||||||
|
|
||||||
|
function buildValidFilterValues(filterInputs) {
|
||||||
|
return filterInputs.reduce((acc, input) => {
|
||||||
|
const key = input.dataset.filterKey;
|
||||||
|
if (!FILTER_KEYS.includes(key)) return acc;
|
||||||
|
if (!acc[key]) acc[key] = new Set();
|
||||||
|
acc[key].add(input.value);
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseStateFromUrl(validFilterValues) {
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const sortParam = params.get(SORT_PARAM) ?? "";
|
||||||
|
const sortValue = VALID_SORT_VALUES.has(sortParam) ? sortParam : "";
|
||||||
|
|
||||||
|
const filters = {
|
||||||
|
industry: [],
|
||||||
|
product: [],
|
||||||
|
company_size: [],
|
||||||
|
location: [],
|
||||||
|
use_cases: []
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const key of FILTER_KEYS) {
|
||||||
|
const valid = validFilterValues[key] ?? new Set();
|
||||||
|
const raw = params
|
||||||
|
.getAll(key)
|
||||||
|
.flatMap((value) => value.split(",").map((part) => part.trim()))
|
||||||
|
.filter(Boolean);
|
||||||
|
filters[key] = [...new Set(raw.filter((value) => valid.has(value)))];
|
||||||
|
}
|
||||||
|
|
||||||
|
return { sortValue, filters };
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncStateToUrl(state) {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
|
||||||
|
url.searchParams.delete(SORT_PARAM);
|
||||||
|
if (state.sortValue) {
|
||||||
|
url.searchParams.set(SORT_PARAM, state.sortValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key of FILTER_KEYS) {
|
||||||
|
url.searchParams.delete(key);
|
||||||
|
(state.filters[key] ?? []).forEach((value) => {
|
||||||
|
url.searchParams.append(key, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextUrl = `${url.pathname}${url.search}${url.hash}`;
|
||||||
|
const currentUrl = `${window.location.pathname}${window.location.search}${window.location.hash}`;
|
||||||
|
|
||||||
|
if (nextUrl !== currentUrl) {
|
||||||
|
window.history.replaceState(null, "", nextUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasActiveState(state) {
|
||||||
|
return (
|
||||||
|
Boolean(state.sortValue) ||
|
||||||
|
FILTER_KEYS.some((key) => (state.filters[key] ?? []).length > 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function initCustomersViewToggle(root) {
|
function initCustomersViewToggle(root) {
|
||||||
const bar = root.querySelector("[data-customers-view-toggle]");
|
const bar = root.querySelector("[data-customers-view-toggle]");
|
||||||
if (!bar) return;
|
if (!bar) return;
|
||||||
@@ -112,7 +188,39 @@ function closeAllFilterAccordions(root) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initCustomersMobileFilters(root, { onClose, onOpen, onApply, onClear }) {
|
function expandAccordionItem(item) {
|
||||||
|
const header = item.querySelector(".customers-case-studies__accordion-header");
|
||||||
|
const panel = header?.nextElementSibling;
|
||||||
|
|
||||||
|
if (!header || !panel?.classList.contains("customers-case-studies__accordion-body")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.classList.add("active");
|
||||||
|
panel.style.maxHeight = `${panel.scrollHeight}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncAccordionExpansion(root, state) {
|
||||||
|
root.querySelectorAll(".customers-case-studies__accordion-item").forEach((item) => {
|
||||||
|
const sortSelect = item.querySelector("[data-sort-select]");
|
||||||
|
const filterInputs = [...item.querySelectorAll("[data-filter-input]")];
|
||||||
|
|
||||||
|
let shouldExpand = false;
|
||||||
|
|
||||||
|
if (sortSelect) {
|
||||||
|
shouldExpand = Boolean(state.sortValue);
|
||||||
|
} else if (filterInputs.length) {
|
||||||
|
const key = filterInputs[0].dataset.filterKey;
|
||||||
|
shouldExpand = (state.filters[key] ?? []).length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldExpand) {
|
||||||
|
expandAccordionItem(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initCustomersMobileFilters(root, { onClose, onOpen, onApply, onClear, onAfterApply }) {
|
||||||
const openBtn = root.querySelector(".customers-case-studies__filter-mobile-button");
|
const openBtn = root.querySelector(".customers-case-studies__filter-mobile-button");
|
||||||
const closeBtn = root.querySelector(".customers-case-studies__filters-close-button");
|
const closeBtn = root.querySelector(".customers-case-studies__filters-close-button");
|
||||||
const applyBtn = root.querySelector(".customers-case-studies__filters-apply-button");
|
const applyBtn = root.querySelector(".customers-case-studies__filters-apply-button");
|
||||||
@@ -138,6 +246,7 @@ function initCustomersMobileFilters(root, { onClose, onOpen, onApply, onClear })
|
|||||||
onApply?.();
|
onApply?.();
|
||||||
panel.classList.remove("active");
|
panel.classList.remove("active");
|
||||||
closeAllFilterAccordions(root);
|
closeAllFilterAccordions(root);
|
||||||
|
onAfterApply?.();
|
||||||
});
|
});
|
||||||
clearBtn?.addEventListener("click", () => onClear?.());
|
clearBtn?.addEventListener("click", () => onClear?.());
|
||||||
}
|
}
|
||||||
@@ -156,6 +265,7 @@ function initCustomersCaseStudies(root) {
|
|||||||
|
|
||||||
const gridCards = [...resultsGrid.querySelectorAll("[data-client-card]")];
|
const gridCards = [...resultsGrid.querySelectorAll("[data-client-card]")];
|
||||||
const listCards = [...resultsList.querySelectorAll("[data-client-card]")];
|
const listCards = [...resultsList.querySelectorAll("[data-client-card]")];
|
||||||
|
const validFilterValues = buildValidFilterValues(filterInputs);
|
||||||
|
|
||||||
let visibleBatchCount = batchSize;
|
let visibleBatchCount = batchSize;
|
||||||
|
|
||||||
@@ -185,6 +295,20 @@ function initCustomersCaseStudies(root) {
|
|||||||
let appliedState = readControlsState();
|
let appliedState = readControlsState();
|
||||||
let draftState = appliedState;
|
let draftState = appliedState;
|
||||||
|
|
||||||
|
const urlState = parseStateFromUrl(validFilterValues);
|
||||||
|
if (hasActiveState(urlState)) {
|
||||||
|
appliedState = urlState;
|
||||||
|
draftState = urlState;
|
||||||
|
applyStateToControls(appliedState);
|
||||||
|
syncAccordionExpansion(root, appliedState);
|
||||||
|
}
|
||||||
|
|
||||||
|
const commitAppliedState = () => {
|
||||||
|
syncStateToUrl(appliedState);
|
||||||
|
refresh();
|
||||||
|
syncAccordionExpansion(root, appliedState);
|
||||||
|
};
|
||||||
|
|
||||||
const getSortedMatchingIds = (state) => {
|
const getSortedMatchingIds = (state) => {
|
||||||
const filters = state.filters;
|
const filters = state.filters;
|
||||||
|
|
||||||
@@ -237,7 +361,7 @@ function initCustomersCaseStudies(root) {
|
|||||||
const onControlsChange = () => {
|
const onControlsChange = () => {
|
||||||
if (isDesktop()) {
|
if (isDesktop()) {
|
||||||
appliedState = readControlsState();
|
appliedState = readControlsState();
|
||||||
refresh();
|
commitAppliedState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
draftState = readControlsState();
|
draftState = readControlsState();
|
||||||
@@ -263,7 +387,7 @@ function initCustomersCaseStudies(root) {
|
|||||||
if (sortSelect) sortSelect.value = "";
|
if (sortSelect) sortSelect.value = "";
|
||||||
filterInputs.forEach((i) => (i.checked = false));
|
filterInputs.forEach((i) => (i.checked = false));
|
||||||
appliedState = readControlsState();
|
appliedState = readControlsState();
|
||||||
refresh();
|
commitAppliedState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sortSelect) sortSelect.value = "";
|
if (sortSelect) sortSelect.value = "";
|
||||||
@@ -273,10 +397,23 @@ function initCustomersCaseStudies(root) {
|
|||||||
onApply: () => {
|
onApply: () => {
|
||||||
if (isDesktop()) return;
|
if (isDesktop()) return;
|
||||||
appliedState = draftState;
|
appliedState = draftState;
|
||||||
refresh();
|
commitAppliedState();
|
||||||
|
},
|
||||||
|
onAfterApply: () => {
|
||||||
|
if (isDesktop()) return;
|
||||||
|
syncAccordionExpansion(root, appliedState);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.addEventListener("popstate", () => {
|
||||||
|
const nextState = parseStateFromUrl(validFilterValues);
|
||||||
|
appliedState = nextState;
|
||||||
|
draftState = nextState;
|
||||||
|
applyStateToControls(appliedState);
|
||||||
|
refresh();
|
||||||
|
syncAccordionExpansion(root, appliedState);
|
||||||
|
});
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user