$elementor->widgets_manager->register_widget_type( new Widgets\FancyList() );
$elementor->widgets_manager->register_widget_type( new Widgets\JustifiedList() );
$elementor->widgets_manager->register_widget_type( new Widgets\Form() );
+ $elementor->widgets_manager->register_widget_type( new Widgets\PatientTour() );
}
protected function _customise_sections() {
--- /dev/null
+<?php
+
+namespace Cube\Elementor\Widgets;
+
+use Elementor\Controls_Manager;
+use Elementor\Utils;
+use Elementor\Repeater;
+
+use function Roots\asset;
+use function Roots\view;
+
+
+class PatientTour extends _Base {
+
+ // Widget name / ID
+ public function get_name() {
+ return 'cube-patient-tour';
+ }
+
+ // Elementor widget title
+ public function get_title() {
+ return __('Parcours patient', 'cube');
+ }
+
+ // Elementor interface icon
+ public function get_icon() {
+ return 'eicon-date';
+ }
+
+ /**
+ * List of scripts the widget depends on.
+ * Used to set scripts dependencies required to run the widget.
+ *
+ * @since 1.0.0
+ * @access public
+ * @return array Widget scripts dependencies.
+ */
+ public function get_script_depends() {
+
+ wp_register_script(
+ 'cube-patient-tour',
+ asset('scripts/patient-tour.js'),
+ ['jquery', 'swiper'], // Dependencies
+ null, // Version
+ true // In footer?
+ );
+
+ // Using Swiper because it is already included and heavily used by Elementor
+
+ return [ 'cube-patient-tour' ];
+ }
+
+ /**
+ * Register the widget controls.
+ * Adds different input fields to allow the user to change and customize the widget settings.
+ *
+ * @since 1.0.0
+ * @access protected
+ */
+ protected function register_controls() {
+
+ $this->start_controls_section(
+ 'section_content',
+ [
+ 'label' => __('Content', 'cube'),
+ ]
+ );
+
+ $repeater = new Repeater();
+
+ $repeater->add_control(
+ 'image',
+ [
+ 'label' => __('Image', 'cube'),
+ 'type' => Controls_Manager::MEDIA,
+ 'default' => [
+ 'url' => Utils::get_placeholder_image_src(),
+ ],
+ ]
+ );
+
+ $repeater->add_control(
+ 'title',
+ [
+ 'label' => __('Title', 'cube'),
+ 'type' => Controls_Manager::TEXT,
+ 'label_block' => true,
+ 'default' => '',
+ ]
+ );
+
+ $this->add_control(
+ 'items',
+ [
+ 'label' => __('Items', 'cube'),
+ 'type' => Controls_Manager::REPEATER,
+ 'fields' => $repeater->get_controls(),
+ 'title_field' => '{{{ title }}}',
+ ]
+ );
+
+ $this->end_controls_section();
+
+ }
+
+ /**
+ * Render the widget output on the frontend.
+ * Written in PHP and used to generate the final HTML.
+ *
+ * @since 1.0.0
+ * @access protected
+ */
+ protected function render() {
+ $items = $this->get_settings('items');
+
+ echo view('widgets/patient-tour', compact('items'));
+ }
+
+}
--- /dev/null
+// ELEMENTOR Trigger
+(function($) {
+ $(window).on('elementor/frontend/init', function () {
+ elementorFrontend.hooks.addAction('frontend/element_ready/cube-patient-tour.default', function ($scope) {
+ const elementSelector = `[data-id="${$scope.data('id')}"] .patient-tour`;
+ const swiperSettings = $(elementSelector).data('swiper'); // Get parameters from data-swiper attribute in HTML
+
+ const swiper = new Swiper(elementSelector, swiperSettings);
+
+ //const lastBullet = $(elementSelector).find(".patient-tour-item").last().get(0).getBoundingClientRect()
+
+ //console.log(lastBullet)
+ });
+ });
+})(jQuery);
\ No newline at end of file
--- /dev/null
+$breakpoint-timeline-horizontal = 768px // When timeline changes to mobile view
+
+.patient-tour
+ width: calc(100% - calc(192px * 2)) !important
+ margin: 0 auto
+ overflow-x: visible
+
+ &-item
+ @apply bg-white flex-col items-center
+ //horizontal-spacing(12.5vw)
+ width: 240px !important
+ constrain(margin-right, 5vw)
+ //height: auto // Needed for fade effect so all slides are same height (height: 100% actually breaks it)
+
+ &:before,
+ &:after
+ @apply bg-blue
+ content: ""
+ position: absolute
+ height: 5px
+ bottom: 27px
+ right: 0
+
+ &:not(:last-child):after
+ constrain(width, 5vw)
+ transform: translateX(100%)
+
+ &:before
+ width: 100%
+
+ &:first-child,&:last-child
+ &:before
+ width: 50%
+
+ &:last-child:before
+ left: 0
+
+
+ +below(950px)
+ padding-left: 10vw
+ padding-right: @padding-left
+
+ +below($breakpoint-timeline-horizontal)
+ flex-direction: column
+ padding-left: 15vw
+ padding-right: @padding-left
+
+ &-image-wrapper
+ display: flex
+ flex: 1 1 40%
+ align-items: center
+ justify-content: center
+ //constrain(margin-right, 5vw)
+
+ +below($breakpoint-timeline-horizontal)
+ margin: 0 0 2em 0
+ flex-grow: 0
+ flex-basis: auto
+ width: 75%
+ max-width: 220px
+
+ &-content
+ flex: 1 1 60%
+
+ > *
+ max-width: 750px
+
+ a
+ @apply text-blue
+
+ &:hover
+ @apply text-yellow
+
+ // Special override for large text so it fits better on smallest screens
+ .text-lg
+ +below(500px)
+ font-size: 1.125rem
+
+ &-position
+ width: 64px
+ height: 64px
+ border-radius: 100px
+
+ // Timeline Pagination
+ &-pagination
+ position: relative
+ display: flex
+ justify-content: space-between
+ align-items: flex-start
+ width: 60% !important
+ //left: 10% !important
+ padding: 0
+ margin: 0 auto
+ z-index: 1
+
+ +below(950px)
+ width: 90% !important
+ left: 5% !important
+
+ +below($breakpoint-timeline-horizontal)
+ display: none
+
+ // Timeline horizontal line
+ &:before
+ content: ''
+ position: absolute
+ top: r(32px)
+ left: 0
+ right: 0
+ height: r(10px)
+ background: #EDEDF4
+ z-index: -1
+
+
+ &-bullet
+ @apply font-display font-normal
+ font-size: 24px
+ display: flex
+ flex-direction: column
+ justify-content: center
+ align-items: center
+ width: auto
+ height: auto
+ border-radius: 0
+ background: transparent
+ opacity: 1
+ text-transform: uppercase
+ outline: none
+ position: relative
+ transition: color 0.3s
+
+ &.active
+ .bullet:before
+ border-color: #FFBF29
+ background: #FFBF29
+
+ &:first-child:before
+ content: ''
+ background: #fff
+ position: absolute
+ width: 50%
+ height: 100%
+ left: 0
+ top: 0
+ z-index: 0
+
+ &:last-child:before
+ content: ''
+ background: #fff
+ position: absolute
+ width: 50%
+ height: 100%
+ right: 0
+ top: 0
+ z-index: 0
+
+ .bullet
+ height: r(68px)
+ width: @height
+ line-height: @height
+ font-size: 52px
+ display: inline-block
+ border-radius: 50%
+ margin-right: 0.5em
+ //margin-bottom: 0.5em
+ text-align: center
+ color: transparent
+ background: transparent
+ position: relative
+ transition: all 0.15s
+ z-index: 1
+
+ // Non-active timeline node
+ &:before
+ content: ''
+ position: absolute
+ top: 50%
+ left: 50%
+ transform: translate(-50%, -50%)
+ width: r(32px)
+ height: @width
+ background: #fff
+ border-radius: 50%
+ border: r(10px) solid #EDEDF4
+ z-index: 0
+ transition: opacity 0.15s
+
+
+ &-title
+ display: block
+ text-align: center
+ .active &
+ color: #FFBF29
+
+ &-active
+ @apply font-bold text-teal bg-transparent
+
+ .bullet
+ @apply text-white bg-teal
+
+ &:before
+ opacity: 0
+
+ // Step number (mobile only)
+ &-step
+ @apply text-center
+
+ //+above($breakpoint-timeline-horizontal)
+ //display: none
+
+ &-title
+ @apply font-body mt-2 mb-6 text-sm font-light
+ min-height: 52px
+ //max-width: 8em
+
+ .bullet
+ @apply font-display bg-blue text-white
+ height: r(64px)
+ width: @height
+ line-height: @height
+ font-size: 40px
+ display: inline-block
+ border-radius: 50%
+ position: relative
+
+ &-line
+ @apply bg-blue
+ width: 1000px
+ height: 5px
+ position: absolute
+ bottom: 0
+
+
+ // Navigation Arrows
+ &-prev, &-next
+ position: absolute
+ top: 50%
+ transform: translateY(-50%)
+ z-index: 10
+ stroke: currentColor
+ transition: color 0.25s
+ outline: none
+
+ &:hover
+ @apply text-blue
+
+ +below(900px)
+ svg
+ width: 20px
+
+ &-prev
+ constrain(left, 5vw)
+
+ +below(950px)
+ left: 2.5vw
+
+ &-next
+ constrain(right, 5vw)
+
+ +below(950px)
+ right: 2.5vw
\ No newline at end of file
--- /dev/null
+{{-- TIMELINE --}}
+@php
+ $settings = [
+ 'slidesPerView' => 'auto',
+ 'loop' => false,
+ 'effect' => 'slide',
+ 'touchEventsTarget' => 'wrapper', // Fix pagination links sometimes going to wrong place
+ 'navigation' => [
+ 'nextEl' => '.patient-tour-next',
+ 'prevEl' => '.patient-tour-prev',
+ ],
+ ];
+
+ $swiper = json_encode($settings);
+
+@endphp
+
+<div class="patient-tour swiper-container" data-swiper="{{ $swiper }}">
+ <div class="swiper-wrapper">
+ @foreach ($items as $key => $item)
+ <div class="patient-tour-item swiper-slide" data-title="{{ $item['title'] }}">
+
+ <div class="patient-tour-item-image-wrapper">
+ @image($item['image']['id'], 'full', ['class' => 'patient-tour-item-image'])
+ </div>
+
+ <div class="patient-tour-step">
+ <h3 class="patient-tour-step-title">{{ $item['title'] }}</h3>
+ <div class="bullet">{{ $loop->iteration }}</div>
+ </div>
+ </div>
+ @endforeach
+ </div>
+ {{--<div class="patient-tour-prev">@svg('carousel-prev', 'stroke-current')</div>
+ <div class="patient-tour-next">@svg('carousel-next', 'stroke-current')</div>--}}
+</div>
+<div class="patient-tour-pagination mb-2v mt-10">
+ <div class="patient-tour-pagination-bullet active">
+ <span class="bullet"></span>
+ <span class="patient-tour-pagination-bullet-title">
+ pre-operative phase - UK
+ </span>
+ </div>
+ <div class="patient-tour-pagination-bullet">
+ <span class="bullet"></span>
+ <span class="patient-tour-pagination-bullet-title">
+ Surgery phase - France
+ </span>
+ </div>
+ <div class="patient-tour-pagination-bullet">
+ <span class="bullet"></span>
+ <span class="patient-tour-pagination-bullet-title">
+ recovery phase - UK
+ </span>
+ </div>
+</div>