-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6d9d9a5
Showing
9 changed files
with
431 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Operating system specific files | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Animated timeline plugin | ||
|
||
This WordPress plugin extends the core Group block to create an animated timeline experience with subtle animation and considerations for [`prefers-reduced-motion`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) respecting a visitors preference for non-essential motion. | ||
|
||
The final pattern is registered within the plugin, but it could also potentially be included directly in a custom WordPress theme. It can also be found on the WordPress Pattern Directory as [Vertical Timeline](https://wordpress.org/patterns/pattern/vertical-timeline/). | ||
|
||
There are two possible styling variations: `animated-timeline` and `animated-timeline animated-timeline--circles`. | ||
|
||
## How to use | ||
|
||
1. Download this plugin as a zip (click on 'Code' and choose 'Download ZIP') | ||
2. Place the un-zipped directory in your WordPress `wp-content/plugins` directory | ||
3. Activate the plugin | ||
4. Create a new post / page and add the 'Animated Timeline' pattern. | ||
5. Save and preview the final animated timeline. | ||
6. Try editing the Advanced -> Additional CSS Classes from `animated-timeline` to `animated-timeline animated-timeline--circles` for the overall pattern's parent Group block to see the circle variation. | ||
|
||
Feel free to fork it and use it however you like! | ||
|
||
## Changelog | ||
|
||
### June 11, 2024 - v1.0.0 | ||
|
||
Initial launch. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<?php | ||
/** | ||
* Plugin Name: Animated Timeline | ||
* Description: Extends the Group block for an animating timeline effect. | ||
* Requires at least: 6.5 | ||
* Requires PHP: 7.4 | ||
* Version: 1.0.0 | ||
* Author: Damon Cook | ||
* License: GPL-2.0-or-later | ||
* License URI: https://www.gnu.org/licenses/gpl-2.0.html | ||
* Text Domain: animated-timeline | ||
*/ | ||
|
||
if ( ! defined( 'ABSPATH' ) ) { | ||
exit; // Exit if accessed directly. | ||
} | ||
|
||
|
||
/** | ||
* Registers the custom script and style for the timeline plugin. | ||
*/ | ||
function animated_timeline_register_scripts() { | ||
|
||
// Register the custom script to be used later. | ||
wp_register_script( | ||
'animated-timeline-script', | ||
plugin_dir_url( __FILE__ ) . '/assets/scripts/core-blocks/group--animated-timeline.js', | ||
array(), | ||
'1.0.0', | ||
true | ||
); | ||
|
||
// Register the custom style to be used later. | ||
wp_register_style( | ||
'animated-timeline-style', | ||
plugin_dir_url( __FILE__ ) . '/assets/styles/core-blocks/group--animated-timeline.css', | ||
array(), | ||
'1.0.0', | ||
); | ||
} | ||
add_action( 'wp_enqueue_scripts', 'animated_timeline_register_scripts' ); | ||
|
||
/** | ||
* Modify the core Group block. | ||
* | ||
* @param string $block_content The block content about to be rendered. | ||
* | ||
* @return string The maybe modified block content. | ||
*/ | ||
function animated_timeline_filter_group_content( $block_content ) { | ||
$processor = new WP_HTML_Tag_Processor( $block_content ); | ||
$counter = 0; | ||
|
||
// Check for the presence of the 'timeline' class. | ||
if ( ! $processor->next_tag( array( 'class_name' => 'animated-timeline' ) ) ) { | ||
return $block_content; | ||
} | ||
|
||
// Loop through each child block with the class name 'wp-block-column'. | ||
while ( $processor->next_tag( array( 'class_name' => 'wp-block-column' ) ) ) { | ||
$processor->add_class( 'animated__item' ); | ||
++$counter; | ||
|
||
switch ( $counter ) { | ||
case 1: | ||
$processor->add_class( 'animated__item--first' ); | ||
break; | ||
case 2: | ||
$processor->add_class( 'animated__item--line' ); | ||
break; | ||
case 3: | ||
$processor->add_class( 'animated__item--last' ); | ||
$counter = 0; | ||
break; | ||
} | ||
} | ||
|
||
$block_content = $processor->get_updated_html(); | ||
|
||
// Enqueue the custom script and style. | ||
wp_enqueue_script( 'animated-timeline-script' ); | ||
wp_enqueue_style( 'animated-timeline-style' ); | ||
|
||
// Return the maybe modified block content. | ||
return $block_content; | ||
} | ||
add_filter( 'render_block_core/group', 'animated_timeline_filter_group_content', 10 ); | ||
|
||
/** | ||
* Registers a block pattern for the timeline plugin. | ||
* | ||
* This function registers a block pattern for the timeline plugin. It checks if the pattern file exists and then registers the pattern using the `register_block_pattern` function. | ||
*/ | ||
function animated_timeline_register_block_pattern() { | ||
$pattern_file = plugin_dir_path( __FILE__ ) . '/patterns/animated-timeline.php'; | ||
|
||
if ( ! file_exists( $pattern_file ) ) { | ||
return; | ||
} | ||
|
||
register_block_pattern( | ||
'animated-timeline/animated-timeline', | ||
require $pattern_file | ||
); | ||
} | ||
add_action( 'init', 'animated_timeline_register_block_pattern' ); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
|
||
/** | ||
* Initializes an Intersection Observer to add the 'loaded' class to elements when they become visible in the viewport. | ||
* The Intersection Observer is set up to observe elements with the class 'animated__item'. | ||
* | ||
* @listens DOMContentLoaded | ||
*/ | ||
document.addEventListener( 'DOMContentLoaded', () => { | ||
const els = document.querySelectorAll( '.animated__item' ); | ||
|
||
const observerOptions = { | ||
root: null, | ||
rootMargin: '0px', | ||
threshold: 0.33, | ||
}; | ||
|
||
/** | ||
* Callback function for the Intersection Observer. | ||
* Adds the 'loaded' class to the target element if it is intersecting. | ||
* | ||
* @param {IntersectionObserverEntry[]} entries - An array of IntersectionObserverEntry objects. | ||
*/ | ||
function observerCallback( entries ) { | ||
entries.forEach( ( entry ) => { | ||
if ( entry.isIntersecting ) { | ||
entry.target.classList.add( 'loaded' ); | ||
} | ||
} ); | ||
} | ||
|
||
const observer = new IntersectionObserver( | ||
observerCallback, | ||
observerOptions | ||
); | ||
|
||
els.forEach( ( el ) => observer.observe( el ) ); | ||
} ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
/* Establish the positioning context for the timeline. */ | ||
.animated-timeline > div { | ||
position: relative; | ||
} | ||
|
||
.animated__item { | ||
visibility: hidden; | ||
} | ||
|
||
.animated__item.loaded { | ||
visibility: visible; | ||
} | ||
|
||
/* First column - initial state */ | ||
.animated-timeline .animated__item--first { | ||
opacity: 0; | ||
transform: translateY(25px); | ||
transition: transform 0.5s, opacity 0.5s; | ||
transition-delay: 0.3s; | ||
} | ||
|
||
/* Last column - initial state */ | ||
.animated-timeline .animated__item--last { | ||
opacity: 0; | ||
transform: translateY(45px); | ||
transition: transform 0.7s, opacity 0.8s; | ||
transition-delay: 0.5s; | ||
} | ||
|
||
/* First and last column - loaded state */ | ||
.animated-timeline .animated__item--first.loaded, | ||
.animated-timeline .animated__item--last.loaded { | ||
opacity: 1; | ||
transform: translateY(0); | ||
} | ||
|
||
/** | ||
* Vertical line animation | ||
* The vertical line is a pseudo-element of the middle column. | ||
*/ | ||
|
||
/* Establish positioning context */ | ||
.animated-timeline .animated__item--line { | ||
position: relative; | ||
visibility: hidden; | ||
} | ||
|
||
/* Vertical line - initial state */ | ||
.animated-timeline .animated__item--line::before { | ||
background-color: inherit; | ||
content: ""; | ||
display: block; | ||
height: 1px; | ||
inset: 0; | ||
opacity: 0; | ||
overflow: hidden; | ||
position: absolute; | ||
transition: height 1.5s, opacity 0.1s; | ||
transition-delay: 0.1s; | ||
transition-origin: top; | ||
visibility: hidden; | ||
width: 100%; | ||
z-index: -1; | ||
} | ||
|
||
/* Vertical line - loaded state */ | ||
.animated-timeline .animated__item--line.loaded::before { | ||
height: 100%; | ||
opacity: 1; | ||
visibility: visible; | ||
} | ||
|
||
/* Middle column - inner text - initial state */ | ||
.animated-timeline .animated__item--line > p { | ||
opacity: 0; | ||
transition: opacity 0.5s; | ||
transition-delay: 1.15s; | ||
visibility: hidden; | ||
} | ||
|
||
/* Middle column - inner text - loaded state */ | ||
.animated-timeline:not(.animated-timeline--circles) .animated__item--line.loaded > p { | ||
opacity: 1; | ||
visibility: visible; | ||
} | ||
|
||
/** | ||
* Circle timeline | ||
* The circle timeline is a variation of the default timeline. | ||
*/ | ||
.animated-timeline--circles .animated__item--line > p { | ||
opacity: 1; | ||
position: relative; | ||
visibility: hidden; | ||
} | ||
|
||
/* Create the circles */ | ||
.animated-timeline--circles .animated__item--line > p::after, | ||
.animated-timeline--circles .animated__item--line > p::before { | ||
background-color: inherit; | ||
border-radius: 50%; | ||
content: ""; | ||
display: block; | ||
height: 1rem; | ||
left: calc(50% - 0.5rem); | ||
opacity: 0; | ||
position: absolute; | ||
top: calc(50% - 0.5rem); | ||
transition: opacity 0.4s, transform 0.6s; | ||
visibility: hidden; | ||
width: 1rem; | ||
} | ||
|
||
/* Background circle - initial state */ | ||
.animated-timeline--circles .animated__item--line > p::after { | ||
background: none; | ||
box-shadow: 0 0 0 4px currentColor; | ||
transform: scale(0); | ||
transition-delay: 1.2s; | ||
z-index: 1; | ||
} | ||
|
||
/* Background circle - loaded state */ | ||
.animated-timeline--circles .animated__item--line.loaded > p::after { | ||
opacity: 0.4; | ||
transform: scale(1); | ||
visibility: visible; | ||
} | ||
|
||
/* Foreground circle - initial state */ | ||
.animated-timeline--circles .animated__item--line > p::before { | ||
transition-delay: 1s; | ||
z-index: 2; | ||
} | ||
|
||
/* Foreground circle - loaded state */ | ||
.animated-timeline--circles .animated__item--line.loaded > p::before { | ||
opacity: 1; | ||
visibility: visible; | ||
} | ||
|
||
@media (prefers-reduced-motion: reduce) { | ||
.animated-timeline *, | ||
.animated-timeline *::after, | ||
.animated-timeline *::before { | ||
opacity: 1 !important; | ||
transition: none !important; | ||
visibility: visible !important; | ||
} | ||
} |
Oops, something went wrong.