Skip to content
Open
2 changes: 2 additions & 0 deletions .stylelintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
tribe-events/
2 changes: 1 addition & 1 deletion .stylelintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "stylelint-config-recommended"
"extends": "@wordpress/stylelint-config"
}
96 changes: 96 additions & 0 deletions assets/js/header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
(function () {
'use strict';

const header = document.querySelector( 'header.wp-block-template-part' );
if ( ! header ) return;

const findHero = () => document.querySelector(
'.entry-content > .ext-hero-section.ext-hero-section--full-screen:first-child'
);

new ResizeObserver( function ( entries ) {
document.documentElement.style.setProperty(
'--ext-header-height',
entries[ 0 ].borderBoxSize[ 0 ].blockSize + 'px'
);
} ).observe( header, { box: 'border-box' } );

// Normal mode: IntersectionObservers against the viewport.
// Original behavior, preserved for real frontend pages.
const setupNormal = () => {
const hero = findHero();
let heroObs;
if ( hero ) {
heroObs = new IntersectionObserver( function ( entries ) {
header.classList.toggle( 'is-past-hero', ! entries[ 0 ].isIntersecting );
}, { rootMargin: '-50% 0px 0px 0px' } );
heroObs.observe( hero );
}

const sentinel = document.createElement( 'div' );
sentinel.style.cssText = 'position:absolute;top:0;left:0;height:16px;width:1px;pointer-events:none;';
document.body.prepend( sentinel );

const scrollObs = new IntersectionObserver( function ( entries ) {
header.classList.toggle( 'is-scrolled', ! entries[ 0 ].isIntersecting );
} );
scrollObs.observe( sentinel );

return () => {
heroObs?.disconnect();
scrollObs.disconnect();
sentinel.remove();
};
};

// Agent mode: rAF-throttled scroll/resize listener with CSS-pixel math.
// The agent's transform: scale() on .wp-site-blocks breaks
// IntersectionObserver geometry, but offsetTop / offsetHeight / scrollTop
// are unaffected by transforms — stable at any scale.
const setupAgent = ( root ) => {
let rafId = 0;
const update = () => {
rafId = 0;
header.classList.toggle( 'is-scrolled', root.scrollTop > 0 );
const hero = findHero();
if ( ! hero ) return;
const heroBottom = hero.offsetTop + hero.offsetHeight;
header.classList.toggle( 'is-past-hero', root.scrollTop > heroBottom );
};
const schedule = () => {
if ( rafId ) return;
rafId = requestAnimationFrame( update );
};

root.addEventListener( 'scroll', schedule, { passive: true } );
window.addEventListener( 'resize', schedule, { passive: true } );
update();

return () => {
if ( rafId ) cancelAnimationFrame( rafId );
root.removeEventListener( 'scroll', schedule );
window.removeEventListener( 'resize', schedule );
};
};

let teardown;
const setup = ( root ) => {
teardown?.();
teardown = root ? setupAgent( root ) : setupNormal();
};

setup( null );

// Optional integration: if the Extendify Agent is active it dispatches
// extendify-agent:layout-shift on open/close (see useLayoutShift in
// SidebarLayout.jsx). When the agent isn't installed this listener is
// simply never invoked — the file works standalone with normal-mode
// IntersectionObservers, identical to its original behavior.
window.addEventListener( 'extendify-agent:layout-shift', function ( event ) {
const open = event?.detail?.open;
const root = open ? document.querySelector( '.wp-site-blocks' ) : null;
// Wait one frame so the agent's transform / overflow changes commit
// before we attach handlers and read geometry.
requestAnimationFrame( () => setup( root ) );
} );
} )();
59 changes: 56 additions & 3 deletions assets/js/navigation-customization.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,70 @@
const hasSiteTitle = !!document.querySelector('header.wp-block-template-part .wp-block-site-title');

const wrapper = document.createElement('div');
wrapper.className = 'site-logo-title wp-block-site-logo';
wrapper.className = 'site-logo-title wp-block-site-logo cloned-for-mobile';
wrapper.innerHTML = `
${logoUrl ? `<img src="${logoUrl}" alt="Site Logo" class="mobile-logo" />` : ''}
${hasSiteTitle ? `<span class="site-title">${siteTitle || ''}</span>` : ''}
`;
container.prepend(wrapper);
}

function injectNavExtras() {
const dialog = document.querySelector('.wp-block-navigation__responsive-dialog');
if (!dialog) return;
if (dialog.querySelector('.ext-nav-extras-mobile')) return;

const header = document.querySelector('header.wp-block-template-part');
if (!header) return;

// Only clone the specific extras (phone / CTA / social). Avoid cloning
// .ext-nav-extras as a wrapper because some header parts use that class
// around the navigation block itself — cloning it would duplicate the
// entire nav.
const extras = header.querySelectorAll(
'.ext-nav-extras-phone, .ext-nav-extras-btn, .ext-nav-extras-social'
);
if (extras.length === 0) return;

const container = document.createElement('div');
container.className = 'ext-nav-extras-mobile cloned-for-mobile';

extras.forEach((el) => {
const clone = el.cloneNode(true);
// Strip identifiers that should be unique per document so the clone
// doesn't collide with the original (id targets, agent-tracked blocks).
clone
.querySelectorAll('[id], [data-extendify-part-block-id], [data-extendify-part-slug], [data-extendify-part]')
.forEach((node) => {
node.removeAttribute('id');
node.removeAttribute('data-extendify-part-block-id');
node.removeAttribute('data-extendify-part-slug');
node.removeAttribute('data-extendify-part');
});
// Force left alignment via inline style: WP generates a
// wp-container-* class for each layout block with its own
// justify-content rule, which has higher specificity than
// swapping .is-content-justification-right/left classes can fight.
[clone, ...clone.querySelectorAll('*')]
.filter((node) => node.classList?.contains('is-content-justification-right')
|| node.classList?.contains('is-content-justification-center'))
.forEach((node) => {
node.style.justifyContent = 'flex-start';
});
container.appendChild(clone);
});

dialog.appendChild(container);
}

function init() {
injectSiteLogoTitle();
injectNavExtras();
}

if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', injectSiteLogoTitle);
document.addEventListener('DOMContentLoaded', init);
} else {
injectSiteLogoTitle();
init();
}
})();
21 changes: 19 additions & 2 deletions functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,23 @@ function extendable_exclude_wc_block_templates( $templates, $query ) {
}
add_filter( 'get_block_templates', 'extendable_exclude_wc_block_templates', 10, 2 );

/**
* Header helper.
*
* @package Extendable
* @since Extendable 2.1.5
*/
function extendable_enqueue_header_scripts() {
wp_enqueue_script(
'extendable-header',
get_template_directory_uri() . '/assets/js/header.js',
array(),
EXTENDABLE_THEME_VERSION,
true
);
}
add_action( 'wp_enqueue_scripts', 'extendable_enqueue_header_scripts' );

/**
* Navigation customizations
*
Expand All @@ -253,11 +270,11 @@ function extendable_enqueue_navigation_customizations() {
true // load in footer
);

wp_localize_script( 'extendable-navigation_customizations', 'ExtendableNavData',
wp_localize_script( 'extendable-navigation_customizations', 'ExtendableNavData',
array(
'logoUrl' => $logo_url,
'siteTitle' => $site_title,
)
)
);
}
endif;
Expand Down
35 changes: 35 additions & 0 deletions parts/header-atlas-beacon.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!-- wp:group {"align":"full","className":"ext-animate\u002d\u002don is-style-ext-preset\u002d\u002dgroup\u002d\u002dnatural-1\u002d\u002dheader-1 ext-header-sticky ext-header-overlay ext-header-glass ext-header-sticky\u002d\u002dfloating-pill","style":{"spacing":{"padding":{"top":"0","bottom":"0"}}},"layout":{"inherit":true,"type":"constrained"}} -->
<div
class="wp-block-group alignfull ext-animate--on is-style-ext-preset--group--natural-1--header-1 ext-header-sticky ext-header-overlay ext-header-glass ext-header-sticky--floating-pill"
style="padding-top: 0; padding-bottom: 0"
>
<!-- wp:group {"align":"wide","style":{"border":{"radius":{"topLeft":"1rem","topRight":"1rem","bottomLeft":"1rem","bottomRight":"1rem"}},"spacing":{"padding":{"top":"var:preset|spacing|20","bottom":"var:preset|spacing|20"}}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"space-between"}} -->
<div
class="wp-block-group alignwide"
style="
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
border-bottom-left-radius: 1rem;
border-bottom-right-radius: 1rem;
padding-top: var(--wp--preset--spacing--20);
padding-bottom: var(--wp--preset--spacing--20);
"
>
<!-- wp:group {"style":{"spacing":{"blockGap":"0.25rem"}},"layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group">
<!-- wp:site-logo {"width":40, "shouldSyncIcon":false} /-->
<!-- wp:site-title {"style":{"typography":{"textTransform":"none"}},"fontSize":"small"} /-->
</div>
<!-- /wp:group -->

<!-- wp:group {"className":"ext-nav-extras","layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group ext-nav-extras">
<!-- wp:navigation {"icon":"menu","overlayBackgroundColor":"background","overlayTextColor":"foreground","layout":{"type":"flex","setCascadingProperties":true,"justifyContent":"right"}} -->
<!-- wp:page-list {"isNavigationChild":true,"showSubmenuIcon":true,"openSubmenusOnClick":false} /-->
<!-- /wp:navigation -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
52 changes: 52 additions & 0 deletions parts/header-catalina-skyline.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!-- wp:group {"align":"full","className":"ext-animate\u002d\u002don is-style-ext-preset\u002d\u002dgroup\u002d\u002dnatural-1\u002d\u002dheader-1 ext-header-sticky ext-header-overlay ext-header\u002d\u002ddark","style":{"spacing":{"padding":{"top":"0","bottom":"0"}}},"layout":{"inherit":true,"type":"constrained"}} -->
<div
class="wp-block-group alignfull ext-animate--on is-style-ext-preset--group--natural-1--header-1 ext-header-sticky ext-header-overlay ext-header--dark"
style="padding-top: 0; padding-bottom: 0"
>
<!-- wp:group {"align":"wide","style":{"border":{"radius":{"topLeft":"1rem","topRight":"1rem","bottomLeft":"1rem","bottomRight":"1rem"}},"spacing":{"padding":{"top":"var:preset|spacing|20","bottom":"var:preset|spacing|20"},"blockGap":"var:preset|spacing|20"}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"space-between"}} -->
<div
class="wp-block-group alignwide"
style="
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
border-bottom-left-radius: 1rem;
border-bottom-right-radius: 1rem;
padding-top: var(--wp--preset--spacing--20);
padding-bottom: var(--wp--preset--spacing--20);
"
>
<!-- wp:group {"style":{"spacing":{"blockGap":"0.25rem"}},"layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group">
<!-- wp:site-logo {"width":48,"shouldSyncIcon":false} /-->
<!-- wp:site-title {"style":{"typography":{"textTransform":"uppercase","fontSize":"14px","fontStyle":"normal","fontWeight":"400","letterSpacing":"0.2em"}}} /-->
</div>
<!-- /wp:group -->

<!-- wp:group {"layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group">
<!-- wp:navigation {"icon":"menu","overlayBackgroundColor":"background","overlayTextColor":"foreground","style":{"typography":{"fontSize":"12px","textTransform":"uppercase","letterSpacing":"0.28em","fontWeight":"600"},"spacing":{"blockGap":"2.5rem"}},"layout":{"type":"flex","setCascadingProperties":true,"justifyContent":"right"}} -->
<!-- wp:page-list /-->
<!-- /wp:navigation -->
</div>
<!-- /wp:group -->

<!-- wp:group {"className":"ext-nav-extras","layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group ext-nav-extras">
<!-- wp:social-links {"iconColor":"foreground","iconColorValue":"var(\u002d\u002dwp\u002d\u002dpreset\u002d\u002dcolor\u002d\u002dforeground)","size":"has-small-icon-size","className":"is-style-logos-only ext-hidden tablet:ext-flex ext-nav-extras-social","style":{"spacing":{"blockGap":"1rem"}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"right"}} -->
<ul
class="wp-block-social-links has-small-icon-size has-icon-color is-style-logos-only ext-hidden tablet:ext-flex ext-nav-extras-social"
>
<!-- wp:social-link {"url":"https://www.instagram.com/","service":"instagram"} /-->

<!-- wp:social-link {"url":"https://www.facebook.com/","service":"facebook"} /-->

<!-- wp:social-link {"url":"https://x.com/","service":"x"} /-->
</ul>
<!-- /wp:social-links -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->

35 changes: 35 additions & 0 deletions parts/header-ceadar-peak.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!-- wp:group {"align":"full","className":"ext-animate\u002d\u002don is-style-ext-preset\u002d\u002dgroup\u002d\u002dnatural-1\u002d\u002dheader-1 ext-header-sticky ext-header-overlay ext-header-glass ext-header-sticky\u002d\u002dfloating-pill ext-header--dark","style":{"spacing":{"padding":{"top":"0","bottom":"0"}}},"layout":{"inherit":true,"type":"constrained"}} -->
<div
class="wp-block-group alignfull ext-animate--on is-style-ext-preset--group--natural-1--header-1 ext-header-sticky ext-header-overlay ext-header-glass ext-header-sticky--floating-pill ext-header--dark"
style="padding-top: 0; padding-bottom: 0"
>
<!-- wp:group {"align":"wide","style":{"border":{"radius":{"topLeft":"1rem","topRight":"1rem","bottomLeft":"1rem","bottomRight":"1rem"}},"spacing":{"padding":{"top":"var:preset|spacing|20","bottom":"var:preset|spacing|20"}}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"space-between"}} -->
<div
class="wp-block-group alignwide"
style="
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
border-bottom-left-radius: 1rem;
border-bottom-right-radius: 1rem;
padding-top: var(--wp--preset--spacing--20);
padding-bottom: var(--wp--preset--spacing--20);
"
>
<!-- wp:group {"style":{"spacing":{"blockGap":"0.25rem"}},"layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group">
<!-- wp:site-logo {"width":40, "shouldSyncIcon":false} /-->
<!-- wp:site-title {"style":{"typography":{"textTransform":"none"}},"fontSize":"small"} /-->
</div>
<!-- /wp:group -->

<!-- wp:group {"className":"ext-nav-extras","layout":{"type":"flex","flexWrap":"nowrap"}} -->
<div class="wp-block-group ext-nav-extras">
<!-- wp:navigation {"icon":"menu","overlayBackgroundColor":"background","overlayTextColor":"foreground","layout":{"type":"flex","setCascadingProperties":true,"justifyContent":"right"}} -->
<!-- wp:page-list {"isNavigationChild":true,"showSubmenuIcon":true,"openSubmenusOnClick":false} /-->
<!-- /wp:navigation -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
Loading