Skip to content

Commit

Permalink
Add new Sidebar Container block to handle sticky sidebar logic (#397)
Browse files Browse the repository at this point in the history
This pulls out the sticky-related JS from the table of contents block, and ports over some CSS from the child themes, so that the sidebar pattern with table of contents can be reused. By consolidating the code here, we can prevent duplicating the CSS across the child themes.
  • Loading branch information
ryelle authored May 8, 2023
1 parent 8031c94 commit 794d704
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 29 deletions.
54 changes: 54 additions & 0 deletions mu-plugins/blocks/sidebar-container/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
/**
* Block Name: Sidebar Container
* Description: A sticky container to be used in 2-column layouts.
* Only added in templates (code), not enabled in the editor.
*
* @package wporg
*/

namespace WordPressdotorg\MU_Plugins\Sidebar_Container_Block;

use function WordPressdotorg\MU_Plugins\Helpers\register_assets_from_metadata;

add_action( 'init', __NAMESPACE__ . '\init' );

/**
* Registers the block using the metadata loaded from the `block.json` file.
* Behind the scenes, it registers also all assets so they can be enqueued
* through the block editor in the corresponding context.
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
function init() {
register_block_type(
__DIR__ . '/build',
array(
'render_callback' => __NAMESPACE__ . '\render',
)
);
}

/**
* Render the block content.
*
* @param array $attributes Block attributes.
* @param string $content Block default content.
* @param WP_Block $block Block instance.
*
* @return string Returns the block markup.
*/
function render( $attributes, $content, $block ) {
$back_to_top = sprintf(
'<p class="has-small-font-size is-link-to-top"><a href="#wp--skip-link--target">%s</a></p>',
esc_html__( '↑ Back to top', 'wporg' )
);

$wrapper_attributes = get_block_wrapper_attributes();
return sprintf(
'<div %1$s>%2$s%3$s</div>',
$wrapper_attributes,
$content,
$back_to_top
);
}
38 changes: 38 additions & 0 deletions mu-plugins/blocks/sidebar-container/postcss/style.pcss
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.wp-block-wporg-sidebar-container .is-link-to-top {
display: none;
}

/* Slot the search & table of contents into a floating sidebar on large screens. */
@media (min-width: 1200px) {
.wp-block-wporg-sidebar-container {
--local--block-end-sidebar--width: 340px;

position: absolute;
top: calc(var(--wp-global-header-offset, 0px) + var(--wp-local-header-offset, 0px));

/* Right offset should be "edge spacing" at minimum, otherwise calculate it to be centered. */
right: max(var(--wp--preset--spacing--edge-space), calc((100% - var(--wp--style--global--wide-size)) / 2));
width: var(--local--block-end-sidebar--width);
margin-top: var(--wp--preset--spacing--edge-space) !important;

&.is-fixed-sidebar {
position: fixed;
}

&.is-bottom-sidebar {
position: absolute;
}

&.is-fixed-sidebar .is-link-to-top,
&.is-bottom-sidebar .is-link-to-top {
display: block;
}
}
}

@media (min-width: 890px) {
/* stylelint-disable selector-id-pattern */
#wp--skip-link--target {
scroll-margin-top: var(--wp-local-header-offset, 0);
}
}
19 changes: 19 additions & 0 deletions mu-plugins/blocks/sidebar-container/src/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "wporg/sidebar-container",
"title": "Sidebar Container",
"icon": "align-pull-right",
"category": "layout",
"description": "A sticky container to be used in 2-column layouts.",
"textdomain": "wporg",
"attributes": {},
"supports": {
"inserter": false,
"__experimentalLayout": true
},
"editorScript": "file:./index.js",
"editorStyle": "file:./editor-style.css",
"style": "file:./style.css",
"viewScript": "file:./view.js"
}
25 changes: 25 additions & 0 deletions mu-plugins/blocks/sidebar-container/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* WordPress dependencies
*/
import { registerBlockType } from '@wordpress/blocks';
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import metadata from './block.json';

function Edit() {
return (
<div { ...useBlockProps() }>
<InnerBlocks />
</div>
);
}

registerBlockType( metadata.name, {
edit: Edit,
save: () => {
return <InnerBlocks.Content />;
},
} );
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,8 @@ function getCustomPropValue( name, element = document.body ) {
}

function onScroll() {
const container = document.querySelector( '.wp-block-wporg-table-of-contents' );
if ( ! container ) {
return;
}

// Only run the scroll code if the sidebar is fixed.
const sidebarContainer = container.parentNode;
const sidebarContainer = document.querySelector( '.wp-block-wporg-sidebar-container' );
if ( ! sidebarContainer || ! sidebarContainer.classList.contains( 'is-fixed-sidebar' ) ) {
return;
}
Expand Down Expand Up @@ -65,26 +60,36 @@ function onScroll() {
}
}

function init() {
const container = document.querySelector( '.wp-block-wporg-table-of-contents' );
function isSidebarWithinViewport( container ) {
// Margin offset from the top of the sidebar.
const gap = getCustomPropValue( '--wp--preset--spacing--edge-space' );
// Usable viewport height.
const viewHeight = window.innerHeight - FIXED_HEADER_HEIGHT;
// Get the height of the sidebar, plus the top margin and 50px for the
// "Back to top" link, which isn't visible until `is-fixed-sidebar` is
// added, therefore not included in the offsetHeight value.
const sidebarHeight = container.offsetHeight + gap + 50;
// If the sidebar is shorter than the view area, apply the class so
// that it's fixed and scrolls with the page content.
return sidebarHeight < viewHeight;
}

function init() {
const container = document.querySelector( '.wp-block-wporg-sidebar-container' );

if ( container ) {
// Usable viewport height.
const viewHeight = window.innerHeight - FIXED_HEADER_HEIGHT;
// Get the height of the sidebar, plus the top margin and 50px for the
// "Back to top" link, which isn't visible until `is-fixed-sidebar` is
// added, therefore not included in the parentNode.offsetHeight value.
const sidebarHeight = container.parentNode?.offsetHeight + gap + 50;
// If the table of contents sidebar is shorter than the view area, apply the
// class so that it's fixed and scrolls with the page content.
if ( sidebarHeight < viewHeight ) {
container.parentNode.classList.add( 'is-fixed-sidebar' );
if ( isSidebarWithinViewport( container ) ) {
container.classList.add( 'is-fixed-sidebar' );
onScroll(); // Run once to avoid footer collisions on load (ex, when linked to #reply-title).
window.addEventListener( 'scroll', onScroll );
}
}

// If there is no table of contents, hide the heading.
if ( ! document.querySelector( '.wp-block-wporg-table-of-contents' ) ) {
const heading = document.querySelector( '.wp-block-wporg-sidebar-container h2' );
heading?.style.setProperty( 'display', 'none' );
}
}

window.addEventListener( 'load', init );
17 changes: 13 additions & 4 deletions mu-plugins/blocks/table-of-contents/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,19 @@ function render( $attributes, $content, $block ) {
return '';
}

$content = '<h2 class="has-charcoal-1-color has-text-color has-inter-font-family has-large-font-size" style="margin-top:0px">';
$content .= __( 'In this article', 'wporg' );
$content .= '</h2>';
$content .= '<ul>';
/**
* Filters the title for the Table of Contents.
*
* @param string $title The title to display.
* @param int $post_id The current post ID.
*/
$title = apply_filters( 'wporg_table_of_contents_heading', __( 'In this article', 'wporg' ), $post->ID );

$content = '<div class="wporg-table-of-contents__header">';
$content .= '<h2>' . esc_html( $title ) . '</h2>';
$content .= '</div>';

$content .= '<ul class="wporg-table-of-contents__list">';

$last_item = false;

Expand Down
30 changes: 24 additions & 6 deletions mu-plugins/blocks/table-of-contents/postcss/style.pcss
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
@media (min-width: 890px) {
/* stylelint-disable selector-id-pattern */
#wp--skip-link--target {
scroll-margin-top: var(--wp-local-header-offset, 0);
.wporg-table-of-contents__header {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;

& h2 {
margin: 0 !important;
color: var(--wp--preset--color--charcoal-1);
line-height: var(--wp--custom--body--large--typography--line-height);
font-family: var(--wp--preset--font-family--inter);
font-size: var(--wp--preset--font-size--large);
}
}

.is-toc-heading {
scroll-margin-top: var(--wp-local-header-offset, 0);
.wporg-table-of-contents__list a {
&:focus-visible {
outline: 1.5px solid var(--wp--preset--color--blueberry-1);
outline-offset: 2px;
box-shadow: none;
border-radius: 2px;
}
}

Expand Down Expand Up @@ -51,3 +63,9 @@
border-left: 2px solid var(--wp--preset--color--blueberry-1);
}
}

@media (min-width: 890px) {
.is-toc-heading {
scroll-margin-top: var(--wp-local-header-offset, 0);
}
}
1 change: 0 additions & 1 deletion mu-plugins/blocks/table-of-contents/src/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,5 @@
}
},
"editorScript": "file:./index.js",
"viewScript": "file:./view.js",
"style": "file:./style.css"
}
1 change: 1 addition & 0 deletions mu-plugins/loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
require_once __DIR__ . '/blocks/language-suggest/language-suggest.php';
require_once __DIR__ . '/blocks/latest-news/latest-news.php';
require_once __DIR__ . '/blocks/notice/index.php';
require_once __DIR__ . '/blocks/sidebar-container/index.php';
require_once __DIR__ . '/blocks/screenshot-preview/block.php';
require_once __DIR__ . '/blocks/site-breadcrumbs/index.php';
require_once __DIR__ . '/blocks/table-of-contents/index.php';
Expand Down

0 comments on commit 794d704

Please sign in to comment.