Add sturdy-slab image asset to the crafts directory

This commit is contained in:
2026-04-25 00:30:30 +03:00
parent 9227f2de30
commit f622c09fd4
38 changed files with 554 additions and 34 deletions

View File

@@ -331,6 +331,101 @@ const topLinks = [
});
};
const normalizeCraftSearch = (value) =>
stripDecorativeSymbols(value)
.toLowerCase()
.replace(/ё/g, 'е')
.replace(/\s+/g, ' ')
.trim();
const bindCraftCatalogFilters = () => {
const catalogNodes = document.querySelectorAll('[data-craft-catalog]');
catalogNodes.forEach((catalogNode) => {
if (!(catalogNode instanceof HTMLElement)) return;
if (catalogNode.dataset.craftBound === 'true') return;
catalogNode.dataset.craftBound = 'true';
const searchInput = catalogNode.querySelector('[data-craft-search]');
const filterButtons = Array.from(catalogNode.querySelectorAll('[data-craft-filter]')).filter(
(node) => node instanceof HTMLButtonElement
);
const groupNodes = Array.from(catalogNode.querySelectorAll('[data-craft-group]')).filter(
(node) => node instanceof HTMLElement
);
const emptyState = catalogNode.querySelector('[data-craft-empty]');
let activeFilter = 'all';
const activeButton = filterButtons.find(
(buttonNode) =>
buttonNode.classList.contains('is-active') ||
buttonNode.getAttribute('aria-pressed') === 'true'
);
if (activeButton?.dataset.craftFilter) {
activeFilter = activeButton.dataset.craftFilter;
}
const applyFilters = () => {
const searchQuery =
searchInput instanceof HTMLInputElement ? normalizeCraftSearch(searchInput.value) : '';
filterButtons.forEach((buttonNode) => {
const isActive = (buttonNode.dataset.craftFilter || 'all') === activeFilter;
buttonNode.classList.toggle('is-active', isActive);
buttonNode.setAttribute('aria-pressed', String(isActive));
});
let visibleCount = 0;
groupNodes.forEach((groupNode) => {
const defaultCategory = groupNode.dataset.craftCategory || '';
const itemNodes = Array.from(groupNode.querySelectorAll('[data-craft-item]')).filter(
(node) => node instanceof HTMLElement
);
let groupVisibleCount = 0;
itemNodes.forEach((itemNode) => {
const itemCategory = itemNode.dataset.craftCategory || defaultCategory;
const itemName =
itemNode.dataset.craftName || itemNode.querySelector('h3')?.textContent || '';
const normalizedName = normalizeCraftSearch(itemName);
const matchesCategory = activeFilter === 'all' || itemCategory === activeFilter;
const matchesSearch = !searchQuery || normalizedName.includes(searchQuery);
const isVisible = matchesCategory && matchesSearch;
itemNode.hidden = !isVisible;
if (isVisible) groupVisibleCount += 1;
});
groupNode.hidden = groupVisibleCount === 0;
visibleCount += groupVisibleCount;
});
if (emptyState instanceof HTMLElement) {
emptyState.hidden = visibleCount > 0;
}
};
filterButtons.forEach((buttonNode) => {
buttonNode.addEventListener('click', () => {
const nextFilter = buttonNode.dataset.craftFilter || 'all';
if (nextFilter === activeFilter) return;
activeFilter = nextFilter;
applyFilters();
});
});
if (searchInput instanceof HTMLInputElement) {
searchInput.addEventListener('input', applyFilters);
searchInput.addEventListener('search', applyFilters);
}
applyFilters();
});
};
const enhanceSidebarGroupLinks = () => {
const targets = [{ label: 'Алкоголь', href: '/alcohol/' }];
const labelNodes = document.querySelectorAll('.sidebar-content details > summary .group-label .large');
@@ -407,6 +502,7 @@ const topLinks = [
decorateSectionIcons();
annotateLinkDestinations();
bindCopyIpChips();
bindCraftCatalogFilters();
setReadProgress();
window.addEventListener('scroll', setReadProgress, { passive: true });
window.addEventListener('resize', setReadProgress);
@@ -425,6 +521,7 @@ const topLinks = [
decorateSectionIcons();
annotateLinkDestinations();
bindCopyIpChips();
bindCraftCatalogFilters();
setReadProgress();
});
</script>