Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PLANET-6530 Add new Secondary Navigation Block #2494

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions assets/src/blocks/SecondaryNavigation/SecondaryNavigationBlock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {SecondaryNavigationEditor} from './SecondaryNavigationEditor';
import {example} from './example';

const {__} = wp.i18n;

const BLOCK_NAME = 'planet4-blocks/secondary-navigation';

export const registerSecondaryNavigationBlock = () => {
const {registerBlockType} = wp.blocks;

registerBlockType(BLOCK_NAME, {
title: 'Secondary Navigation Menu',
description: __('Inserts a secondary navigation menu to the page that leads to different sections of the same page.', 'planet4-blocks-backend'),
icon: 'menu-alt3',
category: 'planet4-blocks-beta',
attributes: {
levels: {
type: 'array',
default: [{heading: 2, link: true}],
},
exampleMenuItems: { // Used for the block's preview, which can't extract items from anything.
type: 'array',
},
},
isExample: {
type: 'boolean',
default: false,
},
supports: {
multiple: false, // Use the block just once per post.
html: false,
},
edit: SecondaryNavigationEditor,
save() {
return null;
},
example,
});
};
66 changes: 66 additions & 0 deletions assets/src/blocks/SecondaryNavigation/SecondaryNavigationEditor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {getHeadingsFromBlocks} from '../TableOfContents/getHeadingsFromBlocks';

const {useSelect} = wp.data;
const {InspectorControls} = wp.blockEditor;
const {PanelBody} = wp.components;
const {__} = wp.i18n;

const renderEdit = () => {
return (
<InspectorControls>
<PanelBody title={__('Learn more about this block', 'planet4-blocks-backend')} initialOpen={false}>
<p className="components-base-control__help">
<a target="_blank" href="https://planet4.greenpeace.org/content/blocks/table-of-contents/" rel="noreferrer">
P4 Handbook - P4 Secondary Navigation Menu
</a>
{' '} &#128203;
</p>
</PanelBody>
</InspectorControls>
);
};

const renderView = attributes => {
const {
levels,
isExample,
exampleMenuItems,
} = attributes;

const blocks = useSelect(select => select('core/block-editor').getBlocks(), []);

const flatHeadings = getHeadingsFromBlocks(blocks, levels);

const menuItems = isExample ? exampleMenuItems : flatHeadings;

return (
<section className="block secondary-navigation-block">
{menuItems.length > 0 ?
<div className="secondary-navigation-menu">
<ul className="secondary-navigation-item">
{menuItems.map(({anchor, content}) => (
<li key={anchor}>
<a
className="secondary-navigation-link"
href={`#${anchor}`}
>
{content}
</a>
</li>
))}
</ul>
</div> :
<div className="EmptyMessage">
{__('There are not any pre-established headings that this block can display in the form of a secondary navigation menu. Please add headings to your page.', 'planet4-blocks-backend')}
</div>
}
</section>
);
};

export const SecondaryNavigationEditor = ({attributes, isSelected}) => (
<>
{isSelected && renderEdit()}
{renderView(attributes)}
</>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {getHeadingsFromDom} from '../TableOfContents/getHeadingsFromDom';

export const SecondaryNavigationFrontend = ({levels}) => {
const headings = getHeadingsFromDom(levels);
const setActive = event => {
const allLinks = document.querySelectorAll('.secondary-navigation-link');
allLinks.forEach(link => link.classList.remove('active'));
event.target.classList.add('active');
};

return (
<section className="block secondary-navigation-block">
<div className="secondary-navigation-menu container">
<ul className="secondary-navigation-item">
{headings.map(({anchor, content}) => (
<li
key={anchor}
>
<a
className="secondary-navigation-link"
href={`#${anchor}`}
onClick={setActive}
>
{content}
</a>
</li>
))}
</ul>
</div>
</section>
);
};
27 changes: 27 additions & 0 deletions assets/src/blocks/SecondaryNavigation/example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export const example = {
viewportWidth: 992,
attributes: {
isExample: true,
exampleMenuItems: [
{
content: 'Title 1',
anchor: 'title-1',
level: 2,
shouldLink: true,
},
{
content: 'Title 2',
anchor: 'title-2',
level: 2,
shouldLink: true,
},
{
content: 'Title 3',
anchor: 'title-3',
level: 2,
shouldLink: true,
},
],
},
};

4 changes: 3 additions & 1 deletion assets/src/blocks/TableOfContents/getHeadingsFromDom.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export const getHeadingsFromDom = selectedLevels => {
}

// Get all heading tags that we need to query
const headingsSelector = selectedLevels.map(level => `:not(.table-of-contents-block) > h${level.heading}`);
const headingsSelector = selectedLevels.map(
level => `:not(.table-of-contents-block):not(.secondary-navigation-block) > h${level.heading}`
);

const usedAnchors = [];

Expand Down
2 changes: 2 additions & 0 deletions assets/src/editorIndex.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {addButtonLinkPasteWarning} from './block-editor/addButtonLinkPasteWarnin
import {addBlockFilters} from './block-editor/BlockFilters';
import {replaceTaxonomyTermSelectors} from './block-editor/replaceTaxonomyTermSelectors';
import {setupImageBlockExtension} from './block-editor/setupImageBlockExtension';
import {registerSecondaryNavigationBlock} from './blocks/SecondaryNavigation/SecondaryNavigationBlock';

wp.domReady(() => {
// Blocks
Expand All @@ -29,6 +30,7 @@ wp.domReady(() => {
registerTimelineBlock();
registerPostsListBlock();
registerTopicLinkBlock();
registerSecondaryNavigationBlock();

// Block Templates
registerBlockTemplates();
Expand Down
2 changes: 2 additions & 0 deletions assets/src/frontendIndex.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import {ColumnsFrontend} from './blocks/Columns/ColumnsFrontend';
import {TopicLinkFrontend} from './blocks/TopicLink/TopicLinkFrontend';
import {setupLightboxForImages} from './blocks/components/Lightbox/setupLightboxForImages';
import {setupParallax} from './blocks/components/Parallax/setupParallax';
import {SecondaryNavigationFrontend} from './blocks/SecondaryNavigation/SecondaryNavigationFrontend';

// Render React components
const COMPONENTS = {
'planet4-blocks/submenu': TableOfContentsFrontend,
'planet4-blocks/happypoint': HappyPointFrontend,
'planet4-blocks/columns': ColumnsFrontend,
'planet4-blocks/topic-link': TopicLinkFrontend,
'planet4-blocks/secondary-navigation': SecondaryNavigationFrontend,
};

document.addEventListener('DOMContentLoaded', () => {
Expand Down
2 changes: 2 additions & 0 deletions assets/src/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {setupClickabelActionsListCards} from './actions_list_clickable_cards';
import {removeNoPostText} from './query-no-posts';
import {removeRelatedPostsSection} from './remove_related_section_no_posts';
import {setupCountrySelector} from './country_selector';
import {makeSecondaryNavigationStickyonScroll} from './sticky_on_scroll_sn';

function requireAll(r) {
r.keys().forEach(r);
Expand All @@ -32,4 +33,5 @@ document.addEventListener('DOMContentLoaded', () => {
removeRelatedPostsSection();
setupClickabelActionsListCards();
setupCountrySelector();
makeSecondaryNavigationStickyonScroll();
});
20 changes: 20 additions & 0 deletions assets/src/js/sticky_on_scroll_sn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Adds class to Secondary Navigation block to make it sticky on scroll
export const makeSecondaryNavigationStickyonScroll = () => {
setTimeout(() => {
const stickyElement = document.querySelector('.secondary-navigation-block');
const container = document.querySelector('.page-content');
const offset = -500;

window.addEventListener('scroll', () => {
const containerRect = container.getBoundingClientRect();
const stickyRect = stickyElement.getBoundingClientRect();

if (containerRect.top <= offset && containerRect.bottom > stickyRect.height + offset) {
stickyElement.classList.add('stuck');
} else {
stickyElement.classList.remove('stuck');
}
});

}, 1000);
};
1 change: 1 addition & 0 deletions assets/src/scss/blocks.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Beta blocks
@import "blocks/ActionsList/ActionsListStyle";
@import "blocks/PostsList/PostsListStyle";
@import "blocks/SecondaryNavigation/SecondaryNavigationStyle";

// P4 Blocks
@import "blocks/Accordion/AccordionStyle";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
.secondary-navigation-block {
margin-left: calc(-50vw - -50%);
width: 100vw;
height: 70px;
padding: 10px;
background: var(--color-background-navigation_bar);
border-bottom: 0 transparent;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
position: relative;

@include small-and-less {
> .container {
max-width: 100%;
}
}
}

.page-content > p,
.page-content > h2 {
z-index: -1;
}

.stuck {
position: fixed;
top: 52px;
left: 0;
}

.secondary-navigation-item {
list-style: none;
display: flex;
justify-content: center;
overflow-x: auto;
flex-wrap: nowrap;
scroll-padding-inline-start: 24px;
gap: 48px;
scrollbar-width: none;

@include small-and-less {
justify-content: flex-start;
}

li {
padding: 5px;
flex-shrink: 0;
text-align: center;
cursor: pointer;
scroll-snap-align: start;

&:has(a.active) {
border-bottom: 4px solid var(--gp-green-400);

a {
color: var(--grey-900) !important;

&:hover {
text-decoration: none;
}
}
}

&:hover {
text-decoration: none;
color: var(--grey-900) !important;
border-bottom: 4px solid var(--gp-green-400);
}
}

&::-webkit-scrollbar {
display: none;
}
}

.secondary-navigation-link {
color: var(--grey-600) !important;
font-weight: var(--font-weight-bold);
font-family: var(--font-family-primary);
font-size: var(--font-size-xxs--font-family-primary);
line-height: var(--line-height-xs--font-family-primary);

&:hover {
text-decoration: none;
}
}
2 changes: 2 additions & 0 deletions src/BlockSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class BlockSettings
self::P4_BLOCKS_PREFIX . '/take-action-boxout',
self::P4_BLOCKS_PREFIX . '/timeline',
self::P4_BLOCKS_PREFIX . '/guestbook',
self::P4_BLOCKS_PREFIX . '/secondary-navigation',
self::HUBSPOT_FORMS_BLOCK,
self::GRAVITY_FORMS_BLOCK,
];
Expand Down Expand Up @@ -93,6 +94,7 @@ class BlockSettings
self::P4_BLOCKS_PREFIX . '/take-action-boxout',
self::P4_BLOCKS_PREFIX . '/timeline',
self::P4_BLOCKS_PREFIX . '/guestbook',
self::P4_BLOCKS_PREFIX . '/secondary-navigation',
self::HUBSPOT_FORMS_BLOCK,
self::GRAVITY_FORMS_BLOCK,
];
Expand Down
Loading