Components
53
Accordion Items Animated Gallery Basic Hero Basic Map Case Studies Feed Case Studies Hero Case Study Hero Case Study Slider Column Content Content Grid Content Image Content Slider Cta Cta Blocks Embed Block Enriched Accordion Error Event Feed Example Features Slider Full Width Image Hero Full Width Media Image And Form Image Content Image Split Content Image Stats Logo Slider Map Post Feed Pricing Publications Feed Simple Accordion Simple Header Simple Hero Solutions Animated Block Split Content Split Content Carousel Split Content Content Split Content Post Split Content Pricing Split Content Video Split Image Hero Stats Slider Team Carousel Team Hero Team Listing Testimonial Case Study Timeline Trivia Bar Two Column Rich Text Vacancies Table Video Video Expand

Solutions Animated Block

View example

Sustainability Consultancy

Explore our consultancy services designed to drive meaningful change. We offer expert guidance in carbon reduction, modern slavery compliance, sustainable procurement, and crafting robust sustainability strategies. Our tailored solutions help organisations improve environmental performance, ensure human rights, and integrate social value into their operations. Dive deeper into our services to see how we can support your journey towards sustainability and operational excellence.

Learn More

Sustainability Tool

Measure and enhance your sustainability efforts with our advanced Sustainability Tool. Our platform offers comprehensive solutions for collecting, managing, and reporting sustainability data. From ESG performance and carbon footprint analysis to EDI metrics, our tools provide the insights needed to refine your strategy and drive impactful change across your operations and supply chain. Discover how our solutions streamline reporting and support your journey towards sustainability.

Learn More

Supplier Development Training Programmes

Our Supply Chain Sustainability School offers customised learning materials, interactive workshops, and expert collaboration. We enhance sustainability skills and knowledge across diverse sectors and regions, supporting organisations in improving sustainability in their supply chains.

Learn More

Morgan Sindall enhances procurement with ISO 20400

Explore
Morgan-Sindall-1

BAM enhances transparency with Scope 3 Carbon Calculator

Explore
BAM cover photo

Scottish SMEs achieve net-zero through sustainability hub

Explore
There are no ACF fields assigned to this component.

				
@import "../../resources/scss/util/variables";
@import "../../resources/scss/util/mixins";

.block-solutions-animated-block {
    padding-top: clamp(40px, 8vw, 140px);
	padding-bottom: clamp(4rem, 8vw, 140px);
    overflow: visible;
    
    @include bp($lg, true) {
        padding-left: 1rem;
        padding-right: 1rem;
    }

    @media (min-width: 1100px) and (max-height: 559px) {
        padding-bottom: 1.5rem;
        padding-top: 2rem;
    }

    .container {
        position: relative;
        max-width: 98%;
        padding-top: calc(var(--site-header-height) / 2);

        @include bp($lg, true) {
            position: initial;
        }

        @media (min-width: 1100px) and (max-height: 559px) {
            padding-top: 2.5rem;
        }
    }

    &__skip {
        position: absolute;
        bottom: 1rem;
        right: 1rem;
        color: var(--white);
        border-color: var(--white) !important;
        text-decoration: none !important;
        z-index: 2;

        @include bp($lg, true) {
            /* bottom: 0; */
            left: 2rem;
            right: unset;
        }

        @media (max-width: $lg) and (min-height: 700px) {
            left: 3rem;
        }

        &:hover {
            background-color: var(--secondary);
            color: var(--primary);
        }
    }

    &__navigation {
        position: absolute;
        top: 8rem;
        right: 2rem;
        z-index: 2;

        display: flex;
            flex-direction: row;
            gap: 1rem;
            button {
                color: var(--white);
                width: 44px;
                height: 44px;
                border-radius: 100px;
                border: solid 1px var(--text-color);
                display: flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                transition: .3s ease-in-out;
                background-position: center;
                background-repeat: no-repeat;
                background-size: 24px;
                background-image: url("data:image/svg+xml,%3Csvg width='27' height='18' viewBox='0 0 27 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M7.16895 16.7598L0.768945 8.75977L7.16895 0.759765' stroke='%23fff'/%3E%3Cpath d='M0.768555 8.75977L26.7686 8.75977' stroke='%23fff'/%3E%3C/svg%3E%0A");

                &.next {
                    transform: rotate(180deg);
                }

                &:hover,
                &:focus {
                    background-color: var(--text-color);
                    background-position: center;
                    background-repeat: no-repeat;
                    background-size: 24px;
                    background-image: url("data:image/svg+xml,%3Csvg width='27' height='18' viewBox='0 0 27 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M7.16895 16.7598L0.768945 8.75977L7.16895 0.759765' stroke='%23383551'/%3E%3Cpath d='M0.768555 8.75977L26.7686 8.75977' stroke='%23383551'/%3E%3C/svg%3E%0A") !important;
                }
            }

        @include bp($lg, true) {
            bottom: 1rem;
            top: unset;
            right: 2rem;
        }

        @media (max-width: $lg) and (min-height: 700px) {
            right: 3rem;
        }
    }

    .row {
        height: 80vh;

        @media (min-width: 1100px) and (max-height: 559px) {
            height: 95vh;
        }

        .col-12 {
            @include bp($lg, true) {
                height: 45vh;
            }
        }
    }

    .solution-wrapper,
    .case-study-wrapper {
        position: relative;
        display: flex;
        align-items: center;
        z-index: 2;

        &__inner {
            transition: opacity .75s, visibility .75s;
        }

        .heading {
            font-weight: 600;

            @media (min-width: 1100px) and (max-height: 559px) {
                font-size: 2rem;
            }
        }

        .heading,
        a {
            position: relative;
            z-index: 2;
        }
    }

    .solution-wrapper {
        justify-content: left;
        font-size: 40px;
        width: 100%;

        &__inner {
            opacity: 0;
            position: absolute;
            transform: translateY(40vh);
            padding: rem-calc(0 80);
            transition: opacity .75s, visibility .75s;

            @include bp($lg, true) {
                transform: translateY(50%);
                padding: rem-calc(25 8);
            }

            @media (max-width: $lg) and (min-height: 700px) {
                width: 100%;
                display: flex;
                justify-content: center;
                align-items: center;
                flex-direction: column;
                height: calc(50vh - var(--site-header-height));

                p.content {
                    margin-bottom: 2rem !important;
                    font-size: 1.25rem !important;
                    text-align: center;
                }

                .heading {
                    text-align: center;
                }
            }

            @media (min-width: 1100px) and (max-height: 700px) {
                padding-left: rem-calc(70);
                padding-right: rem-calc(70);
                transform: translateY(45vh);
            }

            .heading {
                font-weight: 600;

                @media (min-width: 1100px) and (max-height: 700px) {
                    font-size: 2rem;
                }


                @include bp($sm, true) {
                    font-size: 1.4rem;
                }
            }

            p.content {
                font-size: clamp(14px, 2vw, 22px);
                margin-bottom: 0;

                @media (min-width: 1100px) and (max-height: 700px) {
                    font-size: 1.25rem;
                }

                @include bp($sm, true) {
                    font-size: 1rem !important;
                }
            }

            a:hover {
                color: var(--white);
            }
        }
    }
    .case-study-wrapper {
        justify-content: center;
        width: 100%;

        &__inner {
            opacity: 0;
            text-align: center;
            position: absolute;
            transform: translateY(40vh);
            padding: 0 7.5rem;

            @media (min-width: 1100px) and (max-height: 700px) {
                transform: translateY(45vh);
            }

            .btn {
                color: var(--white);
                text-transform: uppercase;
                text-decoration: none;
                font-weight: 600;
                margin-top: 0.5rem;

                &:after {
                    content: '';
                    display: inline-block;
                    width: rem-calc(30);
                    height: rem-calc(30);
                    border-radius: 50%;
                    background-color: transparent;
                    border: 1px solid var(--white);
                    position: absolute;
                    left: 110%;
                    /* top: 50%; */
                    bottom: -30%;
                    transition: all 0.2s ease-out;
                    background-image: url("data:image/svg+xml,%3Csvg width='18' height='27' viewBox='0 0 18 27' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0.870117 19.6006L8.87012 26.0006L16.8701 19.6006' stroke='%23fff'/%3E%3Cpath d='M8.87011 26L8.87012 0' stroke='%23fff'/%3E%3C/svg%3E%0A");
                    background-size: 60% 60%;
                    background-position: center;
                    background-repeat: no-repeat;
                    transform: rotate(-90deg);
                }

                &:hover {
                    color: var(--secondary);
                }
            }

            @include bp($lg, true) {
                transform: translateY(20vh);
                padding: rem-calc(25 40);
                
            }
        }

        .heading {
             /* clamp to 4 lines */
             display: -webkit-box;
             -webkit-line-clamp: 4;
             -webkit-box-orient: vertical;
             overflow: hidden;

             @include bp($lg, true) {
                max-width: rem-calc(400);
             }
        }
    }

    .has-secondary-background-color {
        border-top-left-radius: 40px;
        border-bottom-left-radius: 40px;
        position: relative;

        @include bp($lg, true) {
            border-radius: 40px 40px 0 0 ;
        }

        .heading {
            color: var(--primary);
        }
    }

    .has-primary-background-color {
        --text-color: var(--white);
        border-top-right-radius: 40px;
        border-bottom-right-radius: 40px;
        position: relative;

        @include bp($lg, true) {
            border-radius: 0 0 40px 40px;
            padding-bottom: 4rem;
        }

        .heading {
            color: var(--white);
        }
    }

    .case-study-image-wrapper {
        z-index: -1;
        opacity: 0.2;
        pointer-events: none;
        border-radius: 50px;

        img {
            border-radius: 50px;
        }

        &::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: radial-gradient(circle, transparent 40%, var(--primary) 40.001%);
            z-index: 1;
            pointer-events: none;
            border-radius: 50px;
        }
    }

    &__animation {
        display: flex;
        justify-content: center;
        align-items: center;
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 0;
        pointer-events: none;
        svg {
            width: 100%;
            height: 100%;
            max-width: 90%;
            max-height: 90%;

            circle {
                transition: stroke-dasharray 1s;
            }

            #white-path {
                stroke-width: 2px;
                stroke: var(--white);
                fill: transparent;
                stroke-dasharray: 100 0;
                stroke-opacity: 0.6;
            }

            #dotted-path {
                stroke-width: 2px;
                stroke-dasharray: 50 50;
                stroke: var(--secondary);
                transform: rotate(-90deg);
                fill: var(--primary);
            }
            
            #solid-path {
                stroke-width: 8px;
                /* stroke-dasharray: calc(1 * var(--solution-progress)), calc(100 - (1 * var(--solution-progress))); */
                stroke: var(--secondary);
                transform: rotate(-90deg);
                transform-origin: center;
                fill: transparent;
            }

            .solution-circle {
                fill: var(--white);
                transition: r 1s;

                &.active {
                    r: 30;
                    fill: var(--secondary);
                }

                &.been-active {
                    fill: var(--secondary);
                }
            }
        }
        
        #targets circle {
            cx: 500;
            cy: 50;
            stroke-width: 2px;
        }

        .arc {
            transition: transform 1s;
            transform-origin: center;
        }

        @include bp($md, true) {
            display: none;
        }
    }

    .content {
        color: var(--primary);
        font-family: 'Source Sans 3', sans-serif;
        font-size: clamp(14px, 1vw, 22px);

        @include bp($sm, true) {
            max-height: rem-calc(230);
            overflow: scroll;
            font-size: 1rem !important;
        }
    }

    .has-secondary-background-color {
        background-color: var(--secondary);
    }
}
class SolutionsAnimatedBlock {
	block;
	hotspotQuantity = 7;
	startAt = -90;
	center = {x:100, y:100};
	radius = 100;
	currentIndex = 0;

	constructor(block) {
		this.block = block;
		this.init();
	}

	init() {

		const headings = this.block.querySelectorAll('.solution-wrapper__inner');
		const nums = this.block.querySelectorAll('.case-study-wrapper__inner');
		const images = this.block.querySelectorAll('.case-study-image-wrapper');
		const solutionCircles = this.block.querySelectorAll('.solution-circle');
		const arc = this.block.querySelector('.arc');
		const block = this.block;
		const skip = this.block.querySelector('.block-solutions-animated-block__skip');

		const numOfTransitions = headings.length

		const singleDuration = 750;

		this.block.style.setProperty('--solution-progress', '0');
		const solidPath = this.block.querySelector('.solid-path');
		solidPath.style.strokeDasharray = `0 100`;
		block.setAttribute('data-current-index', '0');
		arc.style.transform = `rotate(0deg)`;
		const scrollBuffer = (4 * window.innerHeight) / headings.length;

		if(!headings.length) return;

		const self = this;

		headings.forEach((heading, index) => {
			if(index < 1) {
				solutionCircles.forEach((circle, i) => {
					if(i < index) {
						circle.classList.add('been-active');
					} else if(index === i) {
						circle.classList.add('active');
					} else {
						circle.classList.remove('active');
						circle.classList.remove('been-active');
					}
				});
				solutionCircles[index].classList.add('active');
				nums[index].style.opacity = 1;
				headings[index].style.opacity = 1;
				images[index].style.opacity = 0.2;
				block.setAttribute('data-current-index', index);
			}
		});

		function setArc(index) {
			solutionCircles[index].classList.add('active');

			// we need to rotate .arc clockwise by 360deg/numOfTransitions * i
				arc.style.transform = `rotate(${360 / numOfTransitions * index}deg)`;

			// Use self.block instead of this.block
			self.block.style.setProperty('--solution-progress', `${(index / numOfTransitions) * 100}`);
			const progress = (index / numOfTransitions) * 100;

			// Use self.block instead of this.block
			const solidPath = self.block.querySelector('.solid-path');
			solidPath.style.strokeDasharray = `${progress} ${(100 - progress)}`;
		}

		// Add event listeners for the .prev and .next buttons to scroll through the timeline by one duration
		const prevButton = this.block.querySelector('.prev');
		const nextButton = this.block.querySelector('.next');

		prevButton.addEventListener('click', (e) => {
			e.preventDefault();
			const currentIndex = parseInt(block.getAttribute('data-current-index'));
			console.log('currentIndex', currentIndex);
			/*
			window.scrollTo({
				top : tl.scrollTrigger.labelToScroll('step-'+prevIndex),
				behavior: 'smooth',
			});
			*/
			if (currentIndex === 0) return;
			const prevIndex = currentIndex - 1;

			nums[currentIndex].style.opacity = 0;
			headings[currentIndex].style.opacity = 0;
			images[currentIndex].style.opacity = 0;

			nums[prevIndex].style.opacity = 1;
			headings[prevIndex].style.opacity = 1;
			images[prevIndex].style.opacity = 0.2;

			if (prevIndex === 0) {
				prevButton.classList.add('disabled');
			} else {
				prevButton.classList.remove('disabled');
			}
			nextButton.classList.remove('disabled');

			setArc(prevIndex);

			block.setAttribute('data-current-index', prevIndex);

		});

		nextButton.addEventListener('click', (e) => {
			e.preventDefault();
			const currentIndex = parseInt(block.getAttribute('data-current-index'));
			// if the current index is the last one, we don't want to go to the next one
			if(currentIndex === numOfTransitions - 1) return;
			const nextIndex = currentIndex + 1;

			/*
			window.scrollTo({
				top: tl.scrollTrigger.labelToScroll('step-'+nextIndex) + scrollBuffer,
				behavior: 'smooth',
			});
			*/
			// set data-current-index to the next index

			nums[currentIndex].style.opacity = 0;
			headings[currentIndex].style.opacity = 0;
			images[currentIndex].style.opacity = 0;

			nums[nextIndex].style.opacity = 1;
			headings[nextIndex].style.opacity = 1;
			images[nextIndex].style.opacity = 0.2;

			if (nextIndex === numOfTransitions - 1) {
				nextButton.classList.add('disabled');
			} else {
				nextButton.classList.remove('disabled');
			}
			prevButton.classList.remove('disabled');

			setArc(nextIndex);

			block.setAttribute('data-current-index', nextIndex);
		});


		// when the block enters the viewport, we want to refresh scrolltrigger - do this using a observer
		const observer = new IntersectionObserver((entries) => {
			if(entries[0].isIntersecting) {
				ScrollTrigger.refresh();
				observer.disconnect();
			}
		});
		observer.observe(block);

	}


}

document.addEventListener('DOMContentLoaded', () => {
	document.querySelectorAll('.block-solutions-animated-block').forEach((block) => {
		new SolutionsAnimatedBlock(block);
	})
});
{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "apiVersion": 2,
    "name": "strategiq/solutions-animated-block",
    "title": "Solutions Animated Block",
    "description": "Example block to be used as a template",
    "category": "strategiq",
    "icon": "strategiq",
    "acf": {
        "mode": "preview",
        "renderTemplate": "block-solutions-animated-block.php"
    },
    "supports": {
        "anchor": true,
        "align": false,
        "color": {
            "background": true,
            "text": false,
            "gradients": true
        },
        "spacing": {
            "padding": [
                "top",
                "bottom"
            ],
            "margin": [
                "top",
                "bottom"
            ]
        }
    },
    "example": {
        "attributes": {
            "mode": "preview",
            "data": {
                "heading_type": "h2",
                "heading_text": "Example - Solutions Animated Block",
                "content": "This is some example content to represent what the content will look like"
            }
        }
    },
    "style": "file:../../assets/css/solutions-animated-block/block-solutions-animated-block.css",
    "viewScript": ["gsap","scrolltrigger", "solutions-animated-block"]
}
Page Title
Page Type
Page URL
There are is no readme file with this component.