diff --git a/website/modules/asset/ui/src/clientSideFiltering.js b/website/modules/asset/ui/src/clientSideFiltering.js new file mode 100644 index 00000000..51a2738b --- /dev/null +++ b/website/modules/asset/ui/src/clientSideFiltering.js @@ -0,0 +1,53 @@ +// Client-side filtering for case studies with page reload + +const shouldInterceptClick = function (link) { + const href = link.getAttribute('href'); + return ( + href && + (href.includes('#filter') || + href.includes('?industry=') || + href.includes('&industry=') || + href.includes('?stack=') || + href.includes('&stack=') || + href.includes('?caseStudyType=') || + href.includes('&caseStudyType=')) + ); +}; + +const handleFilterClick = function (event) { + const filterLink = event.target.closest( + '.tag-link, .remove-tag, .clear-all-link', + ); + if (!filterLink || !shouldInterceptClick(filterLink)) { + return; + } + + event.preventDefault(); + + const href = filterLink.getAttribute('href'); + try { + const url = new URL(href, window.location.origin); + const newUrl = url.pathname + url.search + url.hash; + + history.pushState({ clientSideFilter: true, url: newUrl }, '', newUrl); + window.location.reload(); + } catch { + // Fallback to default navigation if URL construction fails + window.location.href = href; + } +}; + +const handlePopState = function (event) { + if (event.state?.clientSideFilter) { + window.location.reload(); + } +}; + +export const initClientSideFiltering = function () { + if (!document.querySelector('.cs_list')) { + return; + } + + window.addEventListener('popstate', handlePopState); + document.addEventListener('click', handleFilterClick); +}; diff --git a/website/modules/asset/ui/src/index.js b/website/modules/asset/ui/src/index.js index 053ac728..57085586 100644 --- a/website/modules/asset/ui/src/index.js +++ b/website/modules/asset/ui/src/index.js @@ -10,13 +10,12 @@ import { initSmoothCounters } from './smoothCounters'; import lozad from 'lozad'; import { setupTagSearchForInput } from './searchInputHandler'; import { FilterModal } from './filterModal'; +import { initClientSideFiltering } from './clientSideFiltering'; + /* eslint-enable sort-imports */ -// Initialize configuration from data attributes function initConfiguration() { - // Set default fallback value first window.DEFAULT_VISIBLE_TAGS_COUNT = 5; - const container = document.querySelector('.cs_container'); if (container) { const defaultVisibleTags = container.getAttribute( @@ -31,14 +30,11 @@ function initConfiguration() { } } -// Lazy loading function initImageLozad() { - // Lazy loads elements with default selector as '.lozad' const observer = lozad(); observer.observe(); } -// Change fonts for the hero FUTURE word function initFontChanger() { const heroContent = document.querySelector('.sf-hero-content strong'); if (!heroContent) return; @@ -84,7 +80,6 @@ function initCaseStudiesTagFilter({ ); } -// Wrapper function function initializeAllComponents() { initImageLozad(); initAllSwipers(); @@ -94,6 +89,7 @@ function initializeAllComponents() { initPhoneFormatting(); initCaseStudiesTagFilter(); initCaseStudiesFilterHandler(); + initClientSideFiltering(); } // Barba pages @@ -114,7 +110,6 @@ function initBarbaPageTransitions() { // Close menu if it's open const menuButton = document.getElementById('nav-icon'); const menu = document.querySelector('[data-menu]'); - if (menuButton && menu) { menu.classList.remove('open'); menuButton.classList.remove('open'); @@ -126,7 +121,6 @@ function initBarbaPageTransitions() { video.play(); } - // Call the wrapper function to initialize all components initializeAllComponents(); // Initialize Apostrophe forms before removing old content @@ -248,7 +242,6 @@ function initMenuToggle() { // Filter Case Studies modal for Case Studies mobile page function initFilterModal() { - // Only initialize if we're on the case studies page if (!document.querySelector('.cs_list')) { return; } @@ -266,7 +259,6 @@ function initFilterModal() { document.addEventListener('DOMContentLoaded', initFilterModal); -// Initialize after Barba transitions if (typeof barba !== 'undefined') { barba.hooks.after(() => { initFilterModal(); @@ -274,13 +266,10 @@ if (typeof barba !== 'undefined') { } export default () => { - // Initialize configuration first initConfiguration(); - // Init all scripts after first visiting the page initializeAllComponents(); - // Initialize case studies filter handler when DOM is ready apos.util.onReady(() => { initCaseStudiesFilterHandler(); }); @@ -289,8 +278,21 @@ export default () => { initAnchorNavigation(); initMenuToggle(); - // Check if in edit mode - if (apos.adminBar) { - initSmoothCounters(); - } + // Case studies anchor fix + setTimeout(() => { + const { pathname, search, hash } = window.location; + const isCasesPage = pathname.includes('/cases'); + const hasFilterParams = + search.includes('industry') || + search.includes('stack') || + search.includes('caseStudyType') || + hash.includes('filter'); + + if (isCasesPage && hasFilterParams) { + const filterAnchor = document.getElementById('filter'); + if (filterAnchor) filterAnchor.scrollIntoView({ behavior: 'smooth' }); + } + }, 300); + + if (apos.adminBar) initSmoothCounters(); }; diff --git a/website/modules/asset/ui/src/scss/_cases.scss b/website/modules/asset/ui/src/scss/_cases.scss index ef95a28c..9f972729 100644 --- a/website/modules/asset/ui/src/scss/_cases.scss +++ b/website/modules/asset/ui/src/scss/_cases.scss @@ -70,6 +70,7 @@ flex-direction: column; gap: 32px; align-items: center; + min-height: calc(100vh - 330px); @include breakpoint-medium { flex-direction: row; @@ -616,14 +617,15 @@ .filter-anchor { position: relative; - top: -64px; + top: -$mobile-header-height; height: 0; + visibility: hidden; @include breakpoint-medium { - top: -95px; + top: -$desktop-header-height; } } -// Case Study preview card +// Case Study preview card with loading state transition .cs_grid { display: grid; grid-template-columns: 1fr; @@ -632,6 +634,7 @@ opacity: 0; transform: translateY(30px); filter: blur(2px); + transition: opacity 0.3s ease; animation: smoothFadeInUp 1.2s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.2s forwards; diff --git a/website/modules/case-studies-page/views/index.html b/website/modules/case-studies-page/views/index.html index 1e291ceb..18674621 100644 --- a/website/modules/case-studies-page/views/index.html +++ b/website/modules/case-studies-page/views/index.html @@ -1,12 +1,14 @@ {# modules/case-studies-page/views/index.new.html #} {% extends "layout.html" %} {% import '@apostrophecms/pager:macros.html' as pager with context %} {% block main %} -
+
-
- {% area data.page, 'main' %} -
-
+
{% area data.page, 'main' %}
+ +
Filter Case Studies
@@ -165,7 +167,10 @@ {% endif %} {% else %} -
  • +
  • {% if filterType == 'industry' %} {% if tags.length > data.defaultVisibleTagsCount %} -