<link media="all" rel="stylesheet" href="/assets/themes/default/css/timeline.css?cb=">

<div class="timeline" data-module="timeline">
    <div class="grid-x">
        <select class="timeline__dropdown js-dropdown">
            <option value="2019">2019</option>
            <option value="2020">2020</option>
            <option value="2021">2021</option>
            <option value="2022">2022</option>
        </select>
        <div class="timeline__carousel">
            <a href="#" class="timeline__arrow timeline__arrow--right js-timeline-right"></a>
            <a href="#" class="timeline__arrow timeline__arrow--left js-timeline-left"></a>
            <div class="timeline__carousel-slides js-slide-container">
                <div class="timeline__slide-wrapper js-slide" data-slide-index="0">
                    <div class="timeline__slide-image">

                        <div class="image  ">
                            <picture>
                                <source media="(max-width: 840px)" type="" srcset="//via.placeholder.com/423x378" />
                                <source media="(min-width: 841px)" type="" srcset="//via.placeholder.com/423x378" />
                                <img src="//via.placeholder.com/423x378" loading="lazy" alt="Image Alt Text">
                            </picture>
                        </div>
                    </div>
                    <div class="timeline__slide-content">
                        <p class="timeline__slide-date">March 2019</p>
                        <h3 class="timeline__slide-heading">Le Soleil d’Or acquired</h3>
                        <div class="timeline__slide-description">
                            <p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>
                        </div>
                    </div>
                </div>
                <div class="timeline__slide-wrapper js-slide" data-slide-index="1">
                    <div class="timeline__slide-image">

                        <div class="image  ">
                            <picture>
                                <source media="(max-width: 840px)" type="" srcset="//via.placeholder.com/423x378" />
                                <source media="(min-width: 841px)" type="" srcset="//via.placeholder.com/423x378" />
                                <img src="//via.placeholder.com/423x378" loading="lazy" alt="Image Alt Text">
                            </picture>
                        </div>
                    </div>
                    <div class="timeline__slide-content">
                        <p class="timeline__slide-date">April 2019</p>
                        <h3 class="timeline__slide-heading">Le Soleil d’Or acquired</h3>
                        <div class="timeline__slide-description">
                            <p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>
                        </div>
                    </div>
                </div>
                <div class="timeline__slide-wrapper js-slide" data-slide-index="2">
                    <div class="timeline__slide-image">

                        <div class="image  ">
                            <picture>
                                <source media="(max-width: 840px)" type="" srcset="//via.placeholder.com/423x378" />
                                <source media="(min-width: 841px)" type="" srcset="//via.placeholder.com/423x378" />
                                <img src="//via.placeholder.com/423x378" loading="lazy" alt="Image Alt Text">
                            </picture>
                        </div>
                    </div>
                    <div class="timeline__slide-content">
                        <p class="timeline__slide-date">June 2020</p>
                        <h3 class="timeline__slide-heading">Le Soleil d’Or acquired</h3>
                        <div class="timeline__slide-description">
                            <p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>
                        </div>
                    </div>
                </div>
                <div class="timeline__slide-wrapper js-slide" data-slide-index="3">
                    <div class="timeline__slide-image">

                        <div class="image  ">
                            <picture>
                                <source media="(max-width: 840px)" type="" srcset="//via.placeholder.com/423x378" />
                                <source media="(min-width: 841px)" type="" srcset="//via.placeholder.com/423x378" />
                                <img src="//via.placeholder.com/423x378" loading="lazy" alt="Image Alt Text">
                            </picture>
                        </div>
                    </div>
                    <div class="timeline__slide-content">
                        <p class="timeline__slide-date">August 2021</p>
                        <h3 class="timeline__slide-heading">Le Soleil d’Or acquired</h3>
                        <div class="timeline__slide-description">
                            <p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>
                        </div>
                    </div>
                </div>
                <div class="timeline__slide-wrapper js-slide" data-slide-index="4">
                    <div class="timeline__slide-image">

                        <div class="image  ">
                            <picture>
                                <source media="(max-width: 840px)" type="" srcset="//via.placeholder.com/423x378" />
                                <source media="(min-width: 841px)" type="" srcset="//via.placeholder.com/423x378" />
                                <img src="//via.placeholder.com/423x378" loading="lazy" alt="Image Alt Text">
                            </picture>
                        </div>
                    </div>
                    <div class="timeline__slide-content">
                        <p class="timeline__slide-date">November 2021</p>
                        <h3 class="timeline__slide-heading">Le Soleil d’Or acquired</h3>
                        <div class="timeline__slide-description">
                            <p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>
                        </div>
                    </div>
                </div>
                <div class="timeline__slide-wrapper js-slide" data-slide-index="5">
                    <div class="timeline__slide-image">

                        <div class="image  ">
                            <picture>
                                <source media="(max-width: 840px)" type="" srcset="//via.placeholder.com/423x378" />
                                <source media="(min-width: 841px)" type="" srcset="//via.placeholder.com/423x378" />
                                <img src="//via.placeholder.com/423x378" loading="lazy" alt="Image Alt Text">
                            </picture>
                        </div>
                    </div>
                    <div class="timeline__slide-content">
                        <p class="timeline__slide-date">December 2021</p>
                        <h3 class="timeline__slide-heading">Le Soleil d’Or acquired</h3>
                        <div class="timeline__slide-description">
                            <p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>
                        </div>
                    </div>
                </div>
                <div class="timeline__slide-wrapper js-slide" data-slide-index="6">
                    <div class="timeline__slide-image">

                        <div class="image  ">
                            <picture>
                                <source media="(max-width: 840px)" type="" srcset="//via.placeholder.com/423x378" />
                                <source media="(min-width: 841px)" type="" srcset="//via.placeholder.com/423x378" />
                                <img src="//via.placeholder.com/423x378" loading="lazy" alt="Image Alt Text">
                            </picture>
                        </div>
                    </div>
                    <div class="timeline__slide-content">
                        <p class="timeline__slide-date">March 2022</p>
                        <h3 class="timeline__slide-heading">Le Soleil d’Or acquired</h3>
                        <div class="timeline__slide-description">
                            <p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>
                        </div>
                    </div>
                </div>
                <div class="timeline__slide-wrapper js-slide" data-slide-index="7">
                    <div class="timeline__slide-image">

                        <div class="image  ">
                            <picture>
                                <source media="(max-width: 840px)" type="" srcset="//via.placeholder.com/423x378" />
                                <source media="(min-width: 841px)" type="" srcset="//via.placeholder.com/423x378" />
                                <img src="//via.placeholder.com/423x378" loading="lazy" alt="Image Alt Text">
                            </picture>
                        </div>
                    </div>
                    <div class="timeline__slide-content">
                        <p class="timeline__slide-date">April 2022</p>
                        <h3 class="timeline__slide-heading">Le Soleil d’Or acquired</h3>
                        <div class="timeline__slide-description">
                            <p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="timeline__markers">
            <a href="#" class="timeline__arrow timeline__arrow--right js-timeline-right"></a>
            <a href="#" class="timeline__arrow timeline__arrow--left js-timeline-left"></a>
            <span class="timeline__marker-line timeline__marker-line--active"></span>
            <span class="timeline__marker-line"></span>
            <div class="timeline__marker-container">
                <div class="timeline__marker-container-inner js-marker-container">
                    <span class="timeline__marker js-timeline-marker" data-index="0" data-year="2019">
                        <span class="timeline__marker-active-date">2019</span>
                        <span class="timeline__marker-date">2019</span>
                        <span class="timeline__marker-dot">
                            <span class="timeline__marker-dot--outer"></span>
                            <span class="timeline__marker-dot--middle"></span>
                            <span class="timeline__marker-dot--inner"></span>
                        </span>
                    </span>
                    <span class="timeline__marker js-timeline-marker" data-index="1" data-year="2019">
                        <span class="timeline__marker-dot">
                            <span class="timeline__marker-dot--outer"></span>
                            <span class="timeline__marker-dot--middle"></span>
                            <span class="timeline__marker-dot--inner"></span>
                        </span>
                    </span>
                    <span class="timeline__marker js-timeline-marker" data-index="2" data-year="2020">
                        <span class="timeline__marker-active-date">2020</span>
                        <span class="timeline__marker-date">2020</span>
                        <span class="timeline__marker-dot">
                            <span class="timeline__marker-dot--outer"></span>
                            <span class="timeline__marker-dot--middle"></span>
                            <span class="timeline__marker-dot--inner"></span>
                        </span>
                    </span>
                    <span class="timeline__marker js-timeline-marker" data-index="3" data-year="2021">
                        <span class="timeline__marker-active-date">2021</span>
                        <span class="timeline__marker-date">2021</span>
                        <span class="timeline__marker-dot">
                            <span class="timeline__marker-dot--outer"></span>
                            <span class="timeline__marker-dot--middle"></span>
                            <span class="timeline__marker-dot--inner"></span>
                        </span>
                    </span>
                    <span class="timeline__marker js-timeline-marker" data-index="4" data-year="2021">
                        <span class="timeline__marker-dot">
                            <span class="timeline__marker-dot--outer"></span>
                            <span class="timeline__marker-dot--middle"></span>
                            <span class="timeline__marker-dot--inner"></span>
                        </span>
                    </span>
                    <span class="timeline__marker js-timeline-marker" data-index="5" data-year="2021">
                        <span class="timeline__marker-dot">
                            <span class="timeline__marker-dot--outer"></span>
                            <span class="timeline__marker-dot--middle"></span>
                            <span class="timeline__marker-dot--inner"></span>
                        </span>
                    </span>
                    <span class="timeline__marker js-timeline-marker" data-index="6" data-year="2022">
                        <span class="timeline__marker-active-date">2022</span>
                        <span class="timeline__marker-date">2022</span>
                        <span class="timeline__marker-dot">
                            <span class="timeline__marker-dot--outer"></span>
                            <span class="timeline__marker-dot--middle"></span>
                            <span class="timeline__marker-dot--inner"></span>
                        </span>
                    </span>
                    <span class="timeline__marker js-timeline-marker" data-index="7" data-year="2022">
                        <span class="timeline__marker-dot">
                            <span class="timeline__marker-dot--outer"></span>
                            <span class="timeline__marker-dot--middle"></span>
                            <span class="timeline__marker-dot--inner"></span>
                        </span>
                    </span>
                </div>
            </div>
        </div>
    </div>
</div>
{{#if firstInstance}}
<link media="all" rel="stylesheet" href="/assets/themes/{{theme}}/css/timeline.css?cb={{cacheBuster}}">
{{/if}}

<div class="timeline" data-module="timeline">
    <div class="grid-x">
        {{#if years.length}}
        <select class="timeline__dropdown js-dropdown">
            {{#each years}}
                {{#if this}}
                    <option value="{{this}}">{{this}}</option>
                {{/if}}
            {{/each}}
        </select>
        {{/if}}
        <div class="timeline__carousel">
            {{#if milestones.length}}
                <a href="#" class="timeline__arrow timeline__arrow--right js-timeline-right"></a>
                <a href="#" class="timeline__arrow timeline__arrow--left js-timeline-left"></a>
            {{/if}}
            <div class="timeline__carousel-slides js-slide-container">
                {{#each milestones}}
                    <div class="timeline__slide-wrapper js-slide" data-slide-index="{{@index}}">
                        <div class="timeline__slide-image">
                            {{> @image firstInstance=image.firstInstance altText=image.altText caption=image.caption placeholderImageUrl=image.placeholderImageUrl fallbackImageUrl=image.fallbackImageUrl sources=image.sources ratio=image.ratio isOriginalSize=image.isOriginalSize theme=image.theme }}
                        </div>
                        <div class="timeline__slide-content">
                            <p class="timeline__slide-date">{{displayDate}}</p>
                            <h3 class="timeline__slide-heading">{{heading}}</h3>
                            <div class="timeline__slide-description">{{{description}}}</div>
                        </div>
                    </div>
                {{/each}}
            </div>
        </div>
        <div class="timeline__markers">
            {{#if milestones.length}}
                <a href="#" class="timeline__arrow timeline__arrow--right js-timeline-right"></a>
                <a href="#" class="timeline__arrow timeline__arrow--left js-timeline-left"></a>
            {{/if}}
            <span class="timeline__marker-line timeline__marker-line--active"></span>
            <span class="timeline__marker-line"></span>
            <div class="timeline__marker-container">
                <div class="timeline__marker-container-inner js-marker-container">
                    {{#each milestones}}
                        <span class="timeline__marker js-timeline-marker" data-index="{{@index}}" data-year="{{year}}">
                            {{#if isYearMarker}}
                                <span class="timeline__marker-active-date">{{year}}</span>
                                <span class="timeline__marker-date">{{year}}</span>
                            {{/if}}
                            <span class="timeline__marker-dot">
                                <span class="timeline__marker-dot--outer"></span>
                                <span class="timeline__marker-dot--middle"></span>
                                <span class="timeline__marker-dot--inner"></span>
                            </span>
                        </span>
                    {{/each}}
                </div>
            </div>
        </div>
    </div>
</div>
{
  "theme": "default",
  "firstInstance": true,
  "years": [
    2019,
    2020,
    2021,
    2022
  ],
  "milestones": [
    {
      "firstInstance": true,
      "image": {
        "placeholderImageUrl": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA",
        "fallbackImageUrl": "//via.placeholder.com/423x378",
        "theme": "default",
        "altText": "Image Alt Text",
        "sources": [
          {
            "types": "image/jpeg",
            "desktopImageUrl": "//via.placeholder.com/423x378",
            "mobileImageUrl": "//via.placeholder.com/423x378"
          }
        ]
      },
      "displayDate": "March 2019",
      "heading": "Le Soleil d’Or acquired",
      "description": "<p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>",
      "year": 2019,
      "isYearMarker": true
    },
    {
      "image": {
        "placeholderImageUrl": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA",
        "fallbackImageUrl": "//via.placeholder.com/423x378",
        "theme": "default",
        "altText": "Image Alt Text",
        "sources": [
          {
            "types": "image/jpeg",
            "desktopImageUrl": "//via.placeholder.com/423x378",
            "mobileImageUrl": "//via.placeholder.com/423x378"
          }
        ]
      },
      "displayDate": "April 2019",
      "heading": "Le Soleil d’Or acquired",
      "description": "<p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>",
      "year": 2019
    },
    {
      "image": {
        "placeholderImageUrl": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA",
        "fallbackImageUrl": "//via.placeholder.com/423x378",
        "theme": "default",
        "altText": "Image Alt Text",
        "sources": [
          {
            "types": "image/jpeg",
            "desktopImageUrl": "//via.placeholder.com/423x378",
            "mobileImageUrl": "//via.placeholder.com/423x378"
          }
        ]
      },
      "displayDate": "June 2020",
      "heading": "Le Soleil d’Or acquired",
      "description": "<p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>",
      "year": 2020,
      "isYearMarker": true
    },
    {
      "image": {
        "placeholderImageUrl": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA",
        "fallbackImageUrl": "//via.placeholder.com/423x378",
        "theme": "default",
        "altText": "Image Alt Text",
        "sources": [
          {
            "types": "image/jpeg",
            "desktopImageUrl": "//via.placeholder.com/423x378",
            "mobileImageUrl": "//via.placeholder.com/423x378"
          }
        ]
      },
      "displayDate": "August 2021",
      "heading": "Le Soleil d’Or acquired",
      "description": "<p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>",
      "year": 2021,
      "isYearMarker": true
    },
    {
      "image": {
        "placeholderImageUrl": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA",
        "fallbackImageUrl": "//via.placeholder.com/423x378",
        "theme": "default",
        "altText": "Image Alt Text",
        "sources": [
          {
            "types": "image/jpeg",
            "desktopImageUrl": "//via.placeholder.com/423x378",
            "mobileImageUrl": "//via.placeholder.com/423x378"
          }
        ]
      },
      "displayDate": "November 2021",
      "heading": "Le Soleil d’Or acquired",
      "description": "<p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>",
      "year": 2021
    },
    {
      "image": {
        "placeholderImageUrl": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA",
        "fallbackImageUrl": "//via.placeholder.com/423x378",
        "theme": "default",
        "altText": "Image Alt Text",
        "sources": [
          {
            "types": "image/jpeg",
            "desktopImageUrl": "//via.placeholder.com/423x378",
            "mobileImageUrl": "//via.placeholder.com/423x378"
          }
        ]
      },
      "displayDate": "December 2021",
      "heading": "Le Soleil d’Or acquired",
      "description": "<p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>",
      "year": 2021
    },
    {
      "image": {
        "placeholderImageUrl": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA",
        "fallbackImageUrl": "//via.placeholder.com/423x378",
        "theme": "default",
        "altText": "Image Alt Text",
        "sources": [
          {
            "types": "image/jpeg",
            "desktopImageUrl": "//via.placeholder.com/423x378",
            "mobileImageUrl": "//via.placeholder.com/423x378"
          }
        ]
      },
      "displayDate": "March 2022",
      "heading": "Le Soleil d’Or acquired",
      "description": "<p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>",
      "year": "2022",
      "isYearMarker": true
    },
    {
      "image": {
        "placeholderImageUrl": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA",
        "fallbackImageUrl": "//via.placeholder.com/423x378",
        "theme": "default",
        "altText": "Image Alt Text",
        "sources": [
          {
            "types": "image/jpeg",
            "desktopImageUrl": "//via.placeholder.com/423x378",
            "mobileImageUrl": "//via.placeholder.com/423x378"
          }
        ]
      },
      "displayDate": "April 2022",
      "heading": "Le Soleil d’Or acquired",
      "description": "<p>Dart further expanded its hospitality portfolio with the acquisition of the 9-room resort, Le Soleil d’Or, on Cayman Brac, a boutique resort which gained international acclaim its farm-to-table philosophy.</p>",
      "year": 2022
    }
  ]
}
  • Content:
    import { isSmallBreakpoint } from '../../../../js/utils/breakpoints';
    
    export class Timeline {
        constructor(component) {
            this.component = component;
            this.dropdown = this.component.querySelector('.js-dropdown');
            this.leftControls = this.component.querySelectorAll('.js-timeline-left');
            this.rightControls = this.component.querySelectorAll('.js-timeline-right');
            this.timelineMarkers = this.component.querySelectorAll('.js-timeline-marker');
            this.timelineMarkerContainer = this.component.querySelector('.js-marker-container');
            this.timeLineMarkerPosPercent = isSmallBreakpoint() ? 25 : 10;
            this.slides = this.component.querySelectorAll('.js-slide');
            this.slideContainer = this.component.querySelector('.js-slide-container');
            this.activeSlideIndex = 0;
            this.disableDropdownChange = false;
            this.addListeners();
        }
    
        addListeners() {
            this.timelineMarkers.forEach((marker) => {
                marker.addEventListener('click', () => {
                    this.showMilestone(parseInt(marker.dataset.index, 10));
                });
            });
    
            this.dropdown.addEventListener('change', () => {
                this.dropdownChanged();
            });
    
            this.leftControls.forEach((leftControl) => {
                leftControl.addEventListener('click', (e) => {
                    e.preventDefault();
                    if (this.activeSlideIndex !== 0) {
                        this.showMilestone(parseInt(this.activeSlideIndex, 10) - 1);
                    }
                });
            });
    
            this.rightControls.forEach((rightControl) => {
                rightControl.addEventListener('click', (e) => {
                    e.preventDefault();
                    this.showMilestone(parseInt(this.activeSlideIndex, 10) + 1);
                });
            });
    
            window.addEventListener('resize', () => {
                this.timeLineMarkerPosPercent = isSmallBreakpoint() ? 25 : 10;
            });
    
            const config = {
                root: this.slideContainer,
                rootMargin: '100px',
                threshold: 0.5,
            };
            const onIntersection = (entries) => {
                for (let i = 0; i < entries.length; i++) {
                    const entry = entries[i];
                    if (entry.isIntersecting) {
                        const slideIndex = parseInt(entry.target.dataset.slideIndex, 10);
                        if (slideIndex !== this.activeslideIndex) {
                            this.activeSlideIndex = slideIndex;
                            this.setActiveMilestone(slideIndex);
                        }
                        entry.target.classList.add('in-view');
                    } else {
                        entry.target.classList.remove('in-view');
                    }
                }
            };
    
            const observer = new IntersectionObserver(onIntersection, config);
            this.slides.forEach((slide) => {
                observer.observe(slide);
            });
        }
    
        dropdownChanged() {
            const marker = this.component.querySelector(`.js-timeline-marker[data-year='${this.dropdown.value}']`);
            if (marker) {
                // We don't want the drop down changing as the slides are scrolled through if the user has already made a change
                this.disableDropdownChange = true;
                this.showMilestone(parseInt(marker.dataset.index, 10));
                window.setTimeout(() => {
                    // Wait until the timeline has scrolled before allowing the dropdown to automatically change
                    this.disableDropdownChange = false;
                }, 1000);
            }
        }
    
        setActiveMilestone(index) {
            this.hideCarouselControls(index);
            this.setActiveMarker(index);
            this.showMilestone(index);
            this.moveMarkers(index);
            if (!this.disableDropdownChange) {
                this.setDropdown(index);
            }
        }
    
        hideCarouselControls(index) {
            if (parseInt(index, 10) === 0) {
                this.leftControls.forEach((leftControl) => {
                    leftControl.classList.add('hidden');
                });
            } else {
                this.leftControls.forEach((leftControl) => {
                    leftControl.classList.remove('hidden');
                });
            }
    
            if (parseInt(index, 10) === this.slides.length - 1) {
                this.rightControls.forEach((rightControl) => {
                    rightControl.classList.add('hidden');
                });
            } else {
                this.rightControls.forEach((rightControl) => {
                    rightControl.classList.remove('hidden');
                });
            }
        }
    
        setActiveMarker(index) {
            this.timelineMarkers.forEach((marker) => {
                marker.classList.remove('active');
                if (parseInt(marker.dataset.index, 10) === index) {
                    marker.classList.add('active');
                }
                if (parseInt(marker.dataset.index, 10) <= index) {
                    marker.classList.add('viewed');
                } else {
                    marker.classList.remove('viewed');
                }
            });
        }
    
        setDropdown(index) {
            const marker = this.timelineMarkers[index];
            if (this.dropdown.value !== marker.dataset.year) {
                this.dropdown.querySelector(`option[value='${marker.dataset.year}']`).selected = true;
            }
        }
    
        showMilestone(index) {
            if (!this.slides[index]) {
                return;
            }
    
            if (index === this.activeSlideIndex) {
                // It's already showing
                return;
            }
    
            this.activeSlideIndex = index;
    
            let scrollPosition = 0;
            for (let i = 0; i < this.activeSlideIndex; i++) {
                scrollPosition += this.slides[i].offsetWidth;
            }
    
            this.slideContainer.scrollLeft = scrollPosition;
        }
    
        moveMarkers(index) {
            if (!this.slides[index]) {
                return;
            }
    
            const distance = this.timeLineMarkerPosPercent - (this.timeLineMarkerPosPercent * (index + 1));
            this.timelineMarkerContainer.style.transform = `translateX(${distance}%)`;
        }
    }
    
    export default (module) => new Timeline(module);
    
  • URL: /components/raw/timeline/timeline.js
  • Filesystem Path: source/patterns/03-components/media/timeline/timeline.js
  • Size: 6.1 KB
  • Content:
    @import 'source/scss/01-settings/_import';
    @import 'source/scss/02-tools/_import';
    
    @keyframes pulse {
        0% {
            transform: scale(0);
        }
    
        25% {
            transform: scale(3.5);
        }
    
        100% {
            transform: scale(2.5);
        }
    }
    
    @keyframes hoverPulse {
        0% {
            transform: scale(1);
        }
    
        50% {
            transform: scale(1.5);
        }
    
        100% {
            transform: scale(1);
        }
    }
    
    .timeline {
        $this: &;
    
        width: 100%;
    
        &__dropdown {
            @extend %spacer-medium;
            color: $color-steel-grey;
            font-weight: bold;
    
            @include breakpoint(medium) {
                margin-left: auto;
                margin-right: auto;
                max-width: rem(500);
            }
    
            &:hover {
                cursor: pointer;
            }
        }
    
        &__carousel {
            display: block;
            position: relative;
            text-decoration: none;
            width: 100%;
    
            #{$this}__arrow {
                display: none;
                top: 50%;
                transform: translateY(-50%);
                width: rem(40);
    
                @include breakpoint(medium) {
                    display: block;
                }
    
                &--left {
                    left: rem(50);
                }
    
                &--right {
                    right: rem(50);
                }
            }
        }
    
        &__carousel-slides {
            display: flex;
            overflow-x: auto;
            position: relative;
            scroll-behavior: smooth;
            scroll-snap-type: x mandatory;
            scrollbar-color: transparent transparent;   // Hide the scrollbar in FF
            scrollbar-width: thin;
    
            // Hide the scrollbar in Safari, Chrome, Opera and (the new Chromium) Edge
            &::-webkit-scrollbar {
                display: none;
            }
        }
    
        &__arrow {
            cursor: pointer;
            position: absolute;
            width: 100%;
            z-index: 2;
    
            &.hidden {
                display: none;
            }
    
            &::before {
                content: ' ';
                height: 40px;
                position: absolute;
                text-align: center;
                width: 40px;
            }
    
            span {
                @extend %visually-hidden;
            }
    
            &--left {
                &::before {
                    background-image: url('data:image/svg+xml; utf8, <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="20" cy="20" r="20" fill="%230054a6"/><path d="M22 14L16 20L22 26" stroke="%23FFFFFF" stroke-width="2"/></svg>');
                }
            }
    
            &--right {
                &::before {
                    background-image: url('data:image/svg+xml; utf8, <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="20" cy="20" r="20" fill="%230054a6"/><path d="M18,26l6-6-6-6" stroke="%23FFFFFF" stroke-width="2"/></svg>');
                }
            }
    
            @include breakpoint(medium) {
                display: block;
            }
        }
    
        &__slide-wrapper {
            display: flex;
            flex-direction: column;
            flex-shrink: 0;
            margin: 0 rem(5);
            overflow: hidden;
            position: relative;
            scroll-snap-align: center;
            transition: .25s;
            width: 100%;
    
            &.active {
                opacity: 1;
            }
    
            @include breakpoint(medium) {
                flex-direction: row;
                opacity: .5;
                padding: 0 rem(22);
                width: 75%;
    
                &.in-view {
                    opacity: 1;
                }
            }
        }
    
        &__slide-date {
            @extend %p--small;
            color: $color-black;
            margin-bottom: rem(10);
        }
    
        &__slide-heading {
            @extend %heading01;
            @extend %spacer-small;
        }
    
        &__slide-description {
            display: block;
            margin-bottom: rem(40);
        }
    
        &__slide-image {
            @extend %spacer-medium;
            padding-bottom: 120%;
            position: relative;
            width: 100%;
    
            @include breakpoint(medium) {
                margin-left: rem(37);
                margin-right: rem(37);
                padding-bottom: 0;
            }
    
            .image {
                height: 100%;
                left: 0;
                position: absolute;
                top: 0;
                width: 100%;
    
                img {
                    @extend %object-fit-cover;
                    max-width: none;
                }
            }
        }
    
        &__slide-content {
            width: 100%;
    
            @include breakpoint(medium) {
                padding: 0 rem(37);
            }
        }
    
        &__markers {
            overflow: hidden;
            position: relative;
            width: 100%;
    
            @include breakpoint(medium) {
                margin: 0 rem(22);
            }
    
            #{$this}__arrow {
                background: $color-white;
                height: rem(45);
                top: 55%;
                width: rem(45);
                z-index: 1;
    
                &--left {
                    left: 0;
    
                    &::before {
                        right: rem(5);
                    }
                }
    
                &--right {
                    right: 0;
    
                    &::before {
                        left: rem(5);
                    }
                }
    
                @include breakpoint(medium) {
                    display: none;
                }
            }
        }
    
        &__marker-container {
            display: flex;
            height: rem(100);
            transform: translateX(50%);
    
            &-inner {
                display: flex;
                height: 100%;
                transition: .5s;
                width: 100%;
            }
        }
    
        &__marker {
            flex-shrink: 0;
            position: relative;
            width: 25%;
    
            @include breakpoint(medium) {
                width: 10%;
            }
    
            &-line {
                background-color: $color-dark-grey;
                height: rem(2);
                position: absolute;
                right: 0;
                top: 75%;
                transform: translateY(-1px);
                width: 50%;
    
                &--active {
                    background-color: $color-steel-grey;
                    left: 0;
                }
            }
    
            &-dot {
                align-items: center;
                cursor: pointer;
                display: flex;
                height: rem(10);
                justify-content: center;
                position: absolute;
                top: 75%;
                transform: translate(-25%, -50%);
                transition: .25s;
                width: rem(10);
    
                &--outer {
                    background: $color-white;
                    border-radius: 50%;
                    display: block;
                    height: 100%;
                    position: absolute;
                    width: 100%;
                }
    
                &--middle {
                    background-color: $color-white;
                    border: rem(.5) solid $color-steel-grey;
                    border-radius: 50%;
                    display: block;
                    height: rem(10);
                    position: absolute;
                    transition: .25s;
                    width: rem(10);
                    z-index: 0;
                }
    
                &--inner {
                    background-color: $color-dark-grey;
                    border-radius: 50%;
                    display: block;
                    height: rem(10);
                    position: absolute;
                    transition: .25s;
                    width: rem(10);
                    z-index: 1;
    
                    .viewed & {
                        background-color: $color-steel-grey;
                    }
                }
    
                .active & {
    
                    #{$this}__marker-dot--outer {
                        transform: scale(3);
                    }
    
                    #{$this}__marker-dot--middle {
                        animation-duration: .75s;
                        animation-fill-mode: forwards;
                        animation-iteration-count: 1;
                        animation-name: pulse;
                    }
    
                    #{$this}__marker-dot--inner {
                        transform: scale(1.5);
                    }
                }
    
                &:hover {
                    #{$this}__marker-dot--inner {
                        animation-duration: 1s;
                        animation-fill-mode: forwards;
                        animation-iteration-count: infinite;
                        animation-name: hoverPulse;
                        background: $color-steel-grey;
                    }
                }
            }
    
            &-date {
                @extend %p--small;
                color: $color-steel-grey;
                opacity: 1;
                transform: translate(-16px, 40px);
                transition: .25s;
    
                .active & {
                    opacity: 0;
                }
            }
    
            &-active-date {
                @extend %p--small;
                background: $color-steel-grey;
                border-radius: rem(60);
                color: $color-white;
                opacity: 0;
                padding: rem(10) rem(20);
                position: absolute;
                transform: translate(-50%, 20px);
                transition: .5s;
    
                &::after {
                    background: $color-steel-grey;
                    bottom: -5px;
                    content: '';
                    display: block;
                    height: rem(13);
                    left: 50%;
                    position: absolute;
                    transform: rotate(45deg) translate(-25%, 25%);
                    width: rem(13);
                }
    
                .active & {
                    display: block;
                    opacity: 1;
                    transform: translate(-50%, 0);
                }
    
            }
        }
    }
    
  • URL: /components/raw/timeline/timeline.scss
  • Filesystem Path: source/patterns/03-components/media/timeline/timeline.scss
  • Size: 9.3 KB

No notes defined.