diff --git a/modal-popup/partials/style.twig b/modal-popup/partials/style.twig index c0afeab..0ab7e21 100644 --- a/modal-popup/partials/style.twig +++ b/modal-popup/partials/style.twig @@ -414,7 +414,8 @@ {# Modal background color #} {% if modalBackground %} - {# Apply to modal content wrapper (the actual visible modal content) #} + {# Apply to modal dialog and content wrapper (the visible modal) #} + {{ style.background(ModalID ~ ' .qx-modal-dialog', modalBackground) }} {{ style.background(elementSelector, modalBackground) }} {{ style.background(elementSelector ~ '.classic-mode', modalBackground) }} {{ style.background(elementSelector ~ '.cover-mode', modalBackground) }} diff --git a/timeline/config.yml b/timeline/config.yml new file mode 100644 index 0000000..60be59d --- /dev/null +++ b/timeline/config.yml @@ -0,0 +1,382 @@ +name: Timeline +slug: timeline +groups: general +helpId: timeline-element +form: + general: + - name: timeline_items + label: Timeline Items + type: group-repeater + schema: + - name: title + label: Title + type: text + value: Timeline Item Title + + - name: date + label: Date/Time + type: text + value: January 2025 + help: Enter the date or time for this timeline item + + - name: description + label: Description + type: editor + value: Add your timeline item description here. + + - name: image + label: Image + type: media + filters: image + showstyle: true + + - name: link + label: Link + type: link + help: Optional link for the timeline item + + - name: active + label: Active State + type: switch + value: false + help: Mark this item as currently active/highlighted + + - name: layout_settings + label: Layout Settings + type: fields-group + status: open + schema: + - name: layout + label: Layout Type + type: select + value: vertical + options: + vertical: Vertical + horizontal: Horizontal + + - name: alignment + label: Timeline Alignment + type: choose + value: center + responsive: false + options: + left: + label: Left + icon: qxuicon-align-left + center: + label: Center + icon: qxuicon-align-center + right: + label: Right + icon: qxuicon-align-right + + - name: show_connector + label: Show Timeline Connector + type: switch + value: true + help: Display the connecting line between timeline items + + - name: show_markers + label: Show Timeline Markers + type: switch + value: true + help: Display the marker dots/icons on timeline items + + - name: show_arrows + label: Show Arrow Indicators + type: switch + value: false + help: Display arrow indicators connecting timeline items to the main line + + - name: connector_style + label: Connector Style + type: select + value: solid + depends: + show_connector: true + options: + solid: Solid + dashed: Dashed + dotted: Dotted + + - name: connector_position + label: Connector Position + type: select + value: left + depends: + show_connector: true + layout: vertical + options: + left: + label: Left Side + center: + label: Center + right: + label: Right Side + + - name: connector_position_horizontal + label: Connector Position + type: select + value: top + help: Position of the connector line in horizontal layout + depends: + show_connector: true + layout: horizontal + options: + top: + label: Top + center: + label: Center + bottom: + label: Bottom + + - name: items_per_view + label: Items Per View + type: slider + min: 1 + max: 6 + value: 3 + responsive: true + help: Number of timeline items to show at once in horizontal layout and value must be between 1 and 6. + depends: + layout: horizontal + + - name: slider_mode + label: Slider Mode + type: select + value: manual + depends: + layout: horizontal + options: + manual: Manual + auto: Auto Play + + - name: auto_play_speed + label: Auto Play Speed (seconds) + type: slider + min: 1 + max: 10 + suffix: s + value: 3 + depends: + layout: horizontal + slider_mode: auto + + - name: show_navigation + label: Show Navigation Arrows + type: select + value: hover + depends: + layout: horizontal + options: + always: Always Visible + hover: Show on Hover + disabled: Disabled + + - name: slide_as_set + label: Slide As A Set + type: switch + value: false + help: Navigate by full sets of items instead of one item at a time + depends: + layout: horizontal + + - name: content_vertical_alignment + label: Content Vertical Alignment + type: choose + value: center + responsive: false + help: Vertical alignment of content within each timeline item + depends: + layout: horizontal + connector_position_horizontal: ["top", "bottom"] + options: + top: + label: Top + icon: qxuicon-arrow-to-top + center: + label: Center + icon: qxuicon-align-center + bottom: + label: Bottom + icon: qxuicon-arrow-to-bottom + + styles: + - name: timeline_appearance + label: Timeline Appearance + type: fields-group + status: open + schema: + - name: timeline_bg + label: Timeline Background + type: background + popover: true + + - name: timeline_padding + label: Timeline Padding + type: padding + popover: true + + - name: timeline_border + label: Timeline Border + type: border + popover: true + + - name: connector_color + label: Connector Color + type: color + value: "#e5e5e5" + + - name: connector_width + label: Connector Width + type: slider + min: 1 + max: 10 + suffix: px + value: 2 + + - name: item_spacing + label: Item Spacing + type: slider + max: 100 + suffix: px + value: 20 + responsive: true + + - name: item_styles + label: Timeline Item Styles + type: fields-group + schema: + - name: item_bg + label: Item Background + type: background + popover: true + + - name: item_border + label: Item Border + type: border + popover: true + + - name: item_padding + label: Item Padding + type: dimensions + units: px + defaultUnit: px + value: + desktop: + top: 20 + bottom: 20 + left: 20 + right: 20 + + - name: item_shadow + label: Box Shadow + type: box-shadow + popover: true + + - name: content_styles + label: Content Styles + type: fields-group + schema: + - name: title_color + label: Title Color + type: color + value: "#333333" + + - name: title_font + label: Title Typography + type: typography + popover: true + + - name: date_color + label: Date Color + type: color + value: "#666666" + + - name: date_font + label: Date Typography + type: typography + popover: true + + - name: description_color + label: Description Color + type: color + value: "#666666" + + - name: description_font + label: Description Typography + type: typography + popover: true + + - name: hover_effects + label: Hover Effects + type: fields-group + schema: + - name: enable_hover + label: Enable Hover Effects + type: switch + value: true + + - name: hover_item_bg + label: Item Background + type: background + popover: true + depends: + enable_hover: true + + - name: hover_title_color + label: Title Color + type: color + depends: + enable_hover: true + + - name: hover_title_font + label: Title Typography + type: typography + popover: true + depends: + enable_hover: true + + - name: hover_date_color + label: Date Color + type: color + depends: + enable_hover: true + + - name: hover_date_font + label: Date Typography + type: typography + popover: true + depends: + enable_hover: true + + - name: hover_description_color + label: Description Color + type: color + depends: + enable_hover: true + + - name: hover_description_font + label: Description Typography + type: typography + popover: true + depends: + enable_hover: true + + - name: responsive_settings + label: Responsive Settings + type: fields-group + schema: + - name: mobile_layout + label: Mobile Layout + type: select + value: vertical + options: + vertical: Vertical + horizontal: Horizontal + + - name: hide_on_mobile + label: Hide Elements on Mobile + type: switch + value: false + help: Hide certain elements on mobile devices to save space diff --git a/timeline/element.php b/timeline/element.php new file mode 100644 index 0000000..1c9037b --- /dev/null +++ b/timeline/element.php @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/timeline/element.svg b/timeline/element.svg new file mode 100644 index 0000000..e00f026 --- /dev/null +++ b/timeline/element.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/timeline/partials/html.twig b/timeline/partials/html.twig new file mode 100644 index 0000000..ce489ff --- /dev/null +++ b/timeline/partials/html.twig @@ -0,0 +1,189 @@ +{% set id = advanced.identifier.id %} +{% set class = advanced.identifier.class %} +{% set timelineItems = general.timeline_items %} +{% set layout = general.layout_settings.layout %} +{% set alignment = general.layout_settings.alignment %} +{% set showConnector = general.layout_settings.show_connector %} +{% set connectorStyle = general.layout_settings.connector_style %} +{% set connectorPosition = general.layout_settings.connector_position %} +{% set connectorPositionHorizontal = general.layout_settings.connector_position_horizontal %} +{% set contentAlignment = general.layout_settings.content_vertical_alignment %} +{% set showMarkers = general.layout_settings.show_markers is defined ? general.layout_settings.show_markers : true %} +{% set showArrows = general.layout_settings.show_arrows is defined ? general.layout_settings.show_arrows : false %} + +{# Use appropriate connector position based on layout #} +{% set finalConnectorPosition = layout == 'horizontal' ? connectorPositionHorizontal : connectorPosition %} + +{# Content alignment class for horizontal layout #} +{% set contentAlignmentClass = (layout == 'horizontal' and contentAlignment) ? 'qx-timeline-content-align-' ~ contentAlignment : '' %} + +{% set classes = classNames('qx-element qx-element-timeline-v2', + 'qx-timeline-' ~ layout, + 'qx-timeline-align-' ~ alignment, + 'qx-timeline-connector-pos-' ~ finalConnectorPosition, + contentAlignmentClass, + visibilityClass(visibility), + class +) %} + +{% set animation = advanced.animation_fields_group.animation %} +{% set animationRepeat = advanced.animation_fields_group.animation_repeat %} +{% set animationDelay = advanced.animation_fields_group.animation_delay %} +{% set background = advanced.background_fields_group.background %} + +{% embed "animation.twig" with { + "id" : id, + "classes" : classes, + "animation" : animation, + "animationRepeat" : animationRepeat, + "animationDelay" : animationDelay, + "background" : background +} %} + {% block element %} + {% if timelineItems %} +
+ {% if layout == 'vertical' %} +
+ {% if showConnector %} +
+ {% endif %} + {% for item in timelineItems %} +
+ {% if showMarkers %} +
+
+
+ {% endif %} + {% if showArrows %} +
+ {% endif %} + + +
+ {% if item.date %} +
{{ item.date }}
+ {% endif %} + + {% if item.title %} +

+ {% if item.link.url %} + {{ item.title | link(item.link) }} + {% else %} + {{ item.title }} + {% endif %} +

+ {% endif %} + + {% if item.image.source %} +
+ {{ image(item.image.source, item.title, '', '', item.image) }} +
+ {% endif %} + + {% if item.description %} +
+ {{ item.description|raw }} +
+ {% endif %} +
+
+ {% endfor %} +
+ {% else %} + {% set itemsPerView = 3 %} + {% if general.layout_settings.items_per_view %} + {% if general.layout_settings.items_per_view.desktop %} + {% set itemsPerView = general.layout_settings.items_per_view.desktop %} + {% else %} + {% set itemsPerView = general.layout_settings.items_per_view %} + {% endif %} + {% endif %} + {% set autoPlaySpeed = general.layout_settings.auto_play_speed %} + {% if autoPlaySpeed.desktop is defined %} + {% set autoPlaySpeed = autoPlaySpeed.desktop %} + {% elseif autoPlaySpeed.value is defined %} + {% set autoPlaySpeed = autoPlaySpeed.value %} + {% elseif autoPlaySpeed is iterable %} + {% set autoPlaySpeed = autoPlaySpeed|first %} + {% endif %} + + {% if autoPlaySpeed > 100 %} + {% set autoPlaySpeed = (autoPlaySpeed / 1000)|round %} + {% endif %} + +
+ +
+ {% if showConnector %} +
+ + + {% endif %} + +
+ {% for item in timelineItems %} +
+ {% if showMarkers %} +
+
+
+ {% endif %} + {% if showArrows %} +
+ {% endif %} + +
+ {% if item.date %} +
{{ item.date }}
+ {% endif %} + + {% if item.title %} +

+ {% if item.link.url %} + {{ item.title | link(item.link) }} + {% else %} + {{ item.title }} + {% endif %} +

+ {% endif %} + + {% if item.image.source %} +
+ {{ image(item.image.source, item.title, '', '', item.image) }} +
+ {% endif %} + + {% if item.description %} +
+ {{ item.description|raw }} +
+ {% endif %} +
+
+ {% endfor %} +
+
+
+ {% endif %} +
+ {% else %} +
+

Add timeline items to get started

+
+ {% endif %} + {% endblock %} +{% endembed %} diff --git a/timeline/partials/script.twig b/timeline/partials/script.twig new file mode 100644 index 0000000..d1af6c6 --- /dev/null +++ b/timeline/partials/script.twig @@ -0,0 +1,241 @@ +{% set id = advanced.identifier.id %} +{% set enableHover = styles.hover_effects.enable_hover %} +{% set hoverAnimation = styles.hover_effects.hover_animation %} + +{% if mode != 'builder' %} +jQuery(document).ready(function($) { +{% endif %} +{% if mode == 'builder' %} +jQuery(function($) { +{% endif %} + var timelineId = "{{ id }}"; + var $timeline = $('#' + timelineId); + + function initTimelineAnimations() { + if (typeof IntersectionObserver !== 'undefined') { + var observer = new IntersectionObserver(function(entries) { + entries.forEach(function(entry) { + if (entry.isIntersecting) { + var $item = $(entry.target); + $item.addClass('qx-timeline-item-visible'); + + {% if enableHover and hoverAnimation != 'none' %} + setTimeout(function() { + $item.addClass('qx-timeline-item-animated'); + }, 200); + {% endif %} + } + }); + }, { + threshold: 0.1, + rootMargin: '0px 0px -50px 0px' + }); + + $timeline.find('.qx-timeline-item').each(function() { + observer.observe(this); + }); + } else { + $timeline.find('.qx-timeline-item').addClass('qx-timeline-item-visible'); + } + } + + function handleHashNavigation() { + if (window.location.hash) { + var hash = window.location.hash; + var $target = $timeline.find(hash); + + if ($target.length) { + setTimeout(function() { + $('html, body').animate({ + scrollTop: $target.offset().top - 100 + }, 800); + }, 500); + } + } + } + + $timeline.find('.qx-timeline-item a').on('click', function(e) { + var $link = $(this); + var href = $link.attr('href'); + + if (href && href.startsWith('#')) { + e.preventDefault(); + var $target = $(href); + + if ($target.length) { + $('html, body').animate({ + scrollTop: $target.offset().top - 100 + }, 800, function() { + history.pushState(null, null, href); + }); + } + } + }); + + function initTimelineSlider() { + var $horizontalTimeline = $timeline.find('.qx-timeline-horizontal'); + + if ($horizontalTimeline.length) { + var $track = $horizontalTimeline.find('.qx-timeline-slider-track'); + var $items = $track.find('.qx-timeline-item'); + var $prevBtn = $horizontalTimeline.find('.qx-timeline-nav-prev'); + var $nextBtn = $horizontalTimeline.find('.qx-timeline-nav-next'); + + var itemsPerView = parseInt($horizontalTimeline.data('items-per-view')) || 3; + var sliderMode = $horizontalTimeline.data('slider-mode') || 'manual'; + + var slideAsSetAttr = $horizontalTimeline.data('slide-as-set'); + var debugSlideAsSetAttr = $horizontalTimeline.data('debug-slide-as-set'); + var slideAsSet = slideAsSetAttr === true || slideAsSetAttr === 'true'; + + var autoSpeed = 3; + try { + var speedAttr = $horizontalTimeline[0].getAttribute('data-auto-speed'); + if (speedAttr && speedAttr !== '[object Object]' && !isNaN(parseInt(speedAttr))) { + autoSpeed = parseInt(speedAttr); + } + } catch (e) { + autoSpeed = 3; + } + + var currentSlide = 0; + var totalSlides = slideAsSet ? Math.ceil($items.length / itemsPerView) : Math.max(1, $items.length - itemsPerView + 1); + var autoPlayInterval; + + function updateSliderWidth() { + var containerWidth = $horizontalTimeline.find('.qx-timeline-slider-container').width(); + var spacing = 25; + var itemWidth = (containerWidth - (itemsPerView - 1) * spacing) / itemsPerView; + + $items.each(function() { + $(this).css({ + 'width': itemWidth + 'px', + 'flex-shrink': '0', + 'flex-grow': '0' + }); + }); + + var trackWidth = ($items.length * itemWidth) + (($items.length - 1) * spacing); + $track.css('width', trackWidth + 'px'); + } + + function goToSlide(slideIndex) { + if (slideIndex < 0) slideIndex = totalSlides - 1; + if (slideIndex >= totalSlides) slideIndex = 0; + + currentSlide = slideIndex; + var containerWidth = $horizontalTimeline.find('.qx-timeline-slider-container').width(); + var spacing = 25; + var itemWidth = (containerWidth - (itemsPerView - 1) * spacing) / itemsPerView; + + var moveDistance; + if (slideAsSet) { + moveDistance = slideIndex * (itemWidth + spacing) * itemsPerView; + } else { + moveDistance = slideIndex * (itemWidth + spacing); + } + + $track.css('transform', 'translateX(-' + moveDistance + 'px)'); + + $prevBtn.toggleClass('disabled', slideIndex === 0); + $nextBtn.toggleClass('disabled', slideIndex === totalSlides - 1); + } + + function nextSlide() { + goToSlide(currentSlide + 1); + } + + function prevSlide() { + goToSlide(currentSlide - 1); + } + + function startAutoPlay() { + if (sliderMode === 'auto') { + stopAutoPlay(); + autoPlayInterval = setInterval(function() { + nextSlide(); + }, autoSpeed * 1000); + } + } + + function stopAutoPlay() { + if (autoPlayInterval) { + clearInterval(autoPlayInterval); + autoPlayInterval = null; + } + } + + $prevBtn.on('click', function() { + stopAutoPlay(); + prevSlide(); + startAutoPlay(); + }); + + $nextBtn.on('click', function() { + stopAutoPlay(); + nextSlide(); + startAutoPlay(); + }); + + $horizontalTimeline.on('mouseenter', function() { + stopAutoPlay(); + }).on('mouseleave', function() { + startAutoPlay(); + }); + + var startX = 0; + var currentX = 0; + var isDragging = false; + + $track.on('touchstart mousedown', function(e) { + stopAutoPlay(); + isDragging = true; + startX = e.type === 'touchstart' ? e.originalEvent.touches[0].clientX : e.clientX; + e.preventDefault(); + }); + + $(document).on('touchmove mousemove', function(e) { + if (!isDragging) return; + currentX = e.type === 'touchmove' ? e.originalEvent.touches[0].clientX : e.clientX; + e.preventDefault(); + }); + + $(document).on('touchend mouseup', function() { + if (!isDragging) return; + isDragging = false; + + var diffX = startX - currentX; + var threshold = 50; + + if (Math.abs(diffX) > threshold) { + if (diffX > 0) { + nextSlide(); + } else { + prevSlide(); + } + } + startAutoPlay(); + }); + + updateSliderWidth(); + goToSlide(0); + startAutoPlay(); + + $(window).on('resize', function() { + updateSliderWidth(); + }); + } + } + + initTimelineAnimations(); + initTimelineSlider(); + handleHashNavigation(); + + $(window).on('resize', function() { + setTimeout(initTimelineAnimations, 300); + }); +}); +{% if mode != 'builder' %} +{% endif %} +{% if mode == 'builder' %} +{% endif %} diff --git a/timeline/partials/style.twig b/timeline/partials/style.twig new file mode 100644 index 0000000..97f628d --- /dev/null +++ b/timeline/partials/style.twig @@ -0,0 +1,596 @@ +{% include 'global.twig' %} + +{% set id = '#' ~ advanced.identifier.id %} +{% set timelineBg = styles.timeline_appearance.timeline_bg %} +{% set timelinePadding = styles.timeline_appearance.timeline_padding %} +{% set timelineBorder = styles.timeline_appearance.timeline_border %} +{% set connectorColor = styles.timeline_appearance.connector_color %} + +{# Extract slider values with responsive support #} +{% set connectorWidth = (styles.timeline_appearance.connector_width.desktop ?? styles.timeline_appearance.connector_width.value ?? styles.timeline_appearance.connector_width ?: 2) %} +{% set itemSpacing = styles.timeline_appearance.item_spacing %} + +{% set itemBg = styles.item_styles.item_bg %} +{% set itemBorder = styles.item_styles.item_border %} +{% set itemPadding = styles.item_styles.item_padding %} +{% set itemBorderRadius = styles.item_styles.item_border_radius %} +{% set itemShadow = styles.item_styles.item_shadow %} + + +{% set titleColor = styles.content_styles.title_color %} +{% set titleFont = styles.content_styles.title_font %} +{% set dateColor = styles.content_styles.date_color %} +{% set dateFont = styles.content_styles.date_font %} +{% set descriptionColor = styles.content_styles.description_color %} +{% set descriptionFont = styles.content_styles.description_font %} + +{% set enableHover = styles.hover_effects.enable_hover %} +{% set hoverItemBg = styles.hover_effects.hover_item_bg %} +{% set hoverTitleColor = styles.hover_effects.hover_title_color %} +{% set hoverTitleFont = styles.hover_effects.hover_title_font %} +{% set hoverDateColor = styles.hover_effects.hover_date_color %} +{% set hoverDateFont = styles.hover_effects.hover_date_font %} +{% set hoverDescriptionColor = styles.hover_effects.hover_description_color %} +{% set hoverDescriptionFont = styles.hover_effects.hover_description_font %} + +{% set showMarkers = general.layout_settings.show_markers is defined ? general.layout_settings.show_markers : true %} +{% set showArrows = general.layout_settings.show_arrows is defined ? general.layout_settings.show_arrows : false %} +{% set mobileLayout = styles.responsive_settings.mobile_layout %} +{% set hideOnMobile = styles.responsive_settings.hide_on_mobile %} + +{# Timeline Wrapper #} +{{ style.css(id ~ ' .qx-timeline-wrapper', 'position', 'relative') }} +{{ style.background(id ~ ' .qx-timeline-wrapper', timelineBg) }} +{{ style.padding(id ~ ' .qx-timeline-wrapper', timelinePadding) }} +{{ style.border(id ~ ' .qx-timeline-wrapper', timelineBorder) }} + +{# Timeline Base Styles #} +{{ style.css(id ~ ' .qx-timeline', 'position', 'relative') }} +{{ style.css(id ~ ' .qx-timeline', 'list-style', 'none') }} +{{ style.css(id ~ ' .qx-timeline', 'margin', '0') }} +{{ style.css(id ~ ' .qx-timeline', 'padding', '0') }} + +{# Timeline Alignment Styles #} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-left .qx-timeline-content', 'text-align', 'left') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-left .qx-timeline-content', 'margin-left', '45px') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-left .qx-timeline-content', 'margin-right', '45px') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-center .qx-timeline-content', 'text-align', 'center') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-center .qx-timeline-content', 'margin-left', '45px') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-center .qx-timeline-content', 'margin-right', '45px') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-right .qx-timeline-content', 'text-align', 'right') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-right .qx-timeline-content', 'margin-right', '45px') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-right .qx-timeline-content', 'margin-left', '45px') }} + +{# Updated: Center/left/right align images using flexbox #} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-left .qx-timeline-image', 'display', 'flex') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-left .qx-timeline-image', 'justify-content', 'flex-start') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-center .qx-timeline-image', 'display', 'flex') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-center .qx-timeline-image', 'justify-content', 'center') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-right .qx-timeline-image', 'display', 'flex') }} +{{ style.css(id ~ '.qx-timeline-vertical.qx-timeline-align-right .qx-timeline-image', 'justify-content', 'flex-end') }} + +{{ style.css(id ~ ' .qx-timeline-horizontal.qx-timeline-align-left', 'justify-content', 'flex-start') }} +{{ style.css(id ~ ' .qx-timeline-horizontal.qx-timeline-align-center', 'justify-content', 'center') }} +{{ style.css(id ~ ' .qx-timeline-horizontal.qx-timeline-align-right', 'justify-content', 'flex-end') }} + +{# Horizontal Content Alignment #} +{{ style.css(id ~ '.qx-timeline-horizontal.qx-timeline-align-left .qx-timeline-content', 'text-align', 'left') }} +{{ style.css(id ~ '.qx-timeline-horizontal.qx-timeline-align-center .qx-timeline-content', 'text-align', 'center') }} +{{ style.css(id ~ '.qx-timeline-horizontal.qx-timeline-align-right .qx-timeline-content', 'text-align', 'right') }} + +{# Horizontal Image Alignment #} +{{ style.css(id ~ '.qx-timeline-horizontal.qx-timeline-align-left .qx-timeline-image', 'display', 'flex') }} +{{ style.css(id ~ '.qx-timeline-horizontal.qx-timeline-align-left .qx-timeline-image', 'justify-content', 'flex-start') }} +{{ style.css(id ~ '.qx-timeline-horizontal.qx-timeline-align-center .qx-timeline-image', 'display', 'flex') }} +{{ style.css(id ~ '.qx-timeline-horizontal.qx-timeline-align-center .qx-timeline-image', 'justify-content', 'center') }} +{{ style.css(id ~ '.qx-timeline-horizontal.qx-timeline-align-right .qx-timeline-image', 'display', 'flex') }} +{{ style.css(id ~ '.qx-timeline-horizontal.qx-timeline-align-right .qx-timeline-image', 'justify-content', 'flex-end') }} + +{# Timeline Connector #} +{{ style.css(id ~ ' .qx-timeline-connector', 'position', 'absolute') }} +{{ style.css(id ~ ' .qx-timeline-connector', 'background-color', connectorColor) }} +{{ style.css(id ~ ' .qx-timeline-connector', 'width', connectorWidth ~ 'px') }} +{{ style.css(id ~ ' .qx-timeline-connector', 'border-radius', connectorWidth ~ 'px') }} + +{# Connector Styles #} +{{ style.css(id ~ ' .qx-timeline-connector-dashed', 'border-style', 'dashed') }} +{{ style.css(id ~ ' .qx-timeline-connector-dashed', 'border-width', '0 ' ~ connectorWidth ~ 'px') }} +{{ style.css(id ~ ' .qx-timeline-connector-dashed', 'background-color', 'transparent') }} +{{ style.css(id ~ ' .qx-timeline-connector-dashed', 'border-color', connectorColor) }} + +{{ style.css(id ~ ' .qx-timeline-connector-dotted', 'border-style', 'dotted') }} +{{ style.css(id ~ ' .qx-timeline-connector-dotted', 'border-width', '0 ' ~ connectorWidth ~ 'px') }} +{{ style.css(id ~ ' .qx-timeline-connector-dotted', 'background-color', 'transparent') }} +{{ style.css(id ~ ' .qx-timeline-connector-dotted', 'border-color', connectorColor) }} + +{# Horizontal Connector Styles #} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-connector-dashed', 'border-width', connectorWidth ~ 'px 0') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-connector-dotted', 'border-width', connectorWidth ~ 'px 0') }} + +{# Vertical Timeline #} + +{# Global Vertical Connector Styling #} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-connector', 'position', 'absolute') }} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-connector', 'left', '-1px') }} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-connector', 'top', '10px') }} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-connector', 'height', '97.5%') }} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-connector', 'width', connectorWidth ~ 'px') }} + +{# Horizontal Timeline #} +{{ style.css(id ~ ' .qx-timeline-horizontal', 'position', 'relative') }} + +{# Horizontal Slider Container #} +{{ style.css(id ~ ' .qx-timeline-slider-container', 'overflow', 'clip') }} +{{ style.css(id ~ ' .qx-timeline-slider-container', 'width', '100%') }} +{{ style.css(id ~ ' .qx-timeline-slider-container', 'padding-top', '55px') }} + +{# Horizontal Slider Track #} +{{ style.css(id ~ ' .qx-timeline-slider-track', 'display', 'flex') }} +{{ style.css(id ~ ' .qx-timeline-slider-track', 'transition', 'transform 0.6s ease-out') }} +{{ style.css(id ~ ' .qx-timeline-slider-track', 'align-items', 'stretch') }} +{{ style.css(id ~ ' .qx-timeline-slider-track', 'width', 'auto') }} +{% if mode != 'builder' %} +{{ style.css(id ~ ' .qx-timeline-slider-track', 'gap', '25px') }} +{% endif %} + +{# Builder Mode Fixes #} +{% if mode == 'builder' %} +{% set itemsPerView = 3 %} +{% if general.layout_settings.items_per_view %} + {% if general.layout_settings.items_per_view.desktop %} + {% set itemsPerView = general.layout_settings.items_per_view.desktop %} + {% else %} + {% set itemsPerView = general.layout_settings.items_per_view %} + {% endif %} +{% endif %} +{% set gapSize = (itemsPerView - 1) * 25 %} + +{{ style.css(id ~ ' .qx-timeline-horizontal', 'min-height', '280px') }} +{{ style.css(id ~ ' .qx-timeline-slider-container', 'min-height', '280px') }} +{{ style.css(id ~ ' .qx-timeline-slider-container', 'overflow', 'hidden') }} +{{ style.css(id ~ ' .qx-timeline-slider-track', 'flex-wrap', 'nowrap') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'min-width', 'unset') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'max-width', 'unset') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'flex', '0 0 auto') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'margin-right', '0') }} + +{# Current setting-based styles #} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'width', 'calc((100% - ' ~ gapSize ~ 'px) / ' ~ itemsPerView ~ ')') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-item:not(:last-child)', 'margin-right', '25px') }} + +{# Also add data-attribute-based styles as fallback/override #} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-items-per-view="1"] .qx-timeline-item', 'width', 'calc(100% - 0px)') }} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-items-per-view="2"] .qx-timeline-item', 'width', 'calc((100% - 25px) / 2)') }} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-items-per-view="3"] .qx-timeline-item', 'width', 'calc((100% - 50px) / 3)') }} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-items-per-view="4"] .qx-timeline-item', 'width', 'calc((100% - 75px) / 4)') }} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-items-per-view="5"] .qx-timeline-item', 'width', 'calc((100% - 100px) / 5)') }} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-items-per-view="6"] .qx-timeline-item', 'width', 'calc((100% - 125px) / 6)') }} +{% endif %} + +{# Global Horizontal Connector Styling #} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-connector', 'position', 'absolute') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-connector', 'top', '35px') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-connector', 'left', '0') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-connector', 'width', '100%') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-connector', 'height', connectorWidth ~ 'px') }} + +{# Horizontal Navigation Arrows #} +{{ style.css(id ~ ' .qx-timeline-nav', 'position', 'absolute') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'top', '20px') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'z-index', '10') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'background', 'rgba(0, 0, 0, 0.7)') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'color', 'white') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'border', 'none') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'border-radius', '50%') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'width', '32px') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'height', '32px') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'display', 'flex') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'align-items', 'center') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'justify-content', 'center') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'cursor', 'pointer') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'transition', 'all 0.3s ease') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'opacity', '0') }} +{{ style.css(id ~ ' .qx-timeline-nav', 'pointer-events', 'none') }} + +{{ style.css(id ~ ' .qx-timeline-nav:hover', 'background', 'rgba(0, 0, 0, 0.9)') }} + +{# Navigation Visibility States #} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-show-nav="always"] .qx-timeline-nav', 'opacity', '1') }} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-show-nav="always"] .qx-timeline-nav', 'pointer-events', 'auto') }} + +{# Disabled state #} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-show-nav="disabled"] .qx-timeline-nav', 'opacity', '0') }} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-show-nav="disabled"] .qx-timeline-nav', 'pointer-events', 'none') }} + +{# Hover state #} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-show-nav="hover"] .qx-timeline-nav', 'opacity', '0 !important') }} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-show-nav="hover"] .qx-timeline-nav', 'pointer-events', 'none') }} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-show-nav="hover"]:hover .qx-timeline-nav', 'opacity', '1 !important') }} +{{ style.css(id ~ ' .qx-timeline-horizontal[data-show-nav="hover"]:hover .qx-timeline-nav', 'pointer-events', 'auto') }} + +{# Timeline Items #} +{{ style.css(id ~ ' .qx-timeline-item', 'position', 'relative') }} +{{ style.css(id ~ ' .qx-timeline-item', 'margin-bottom', '0') }} +{{ style.responsiveCss(id ~ ' .qx-timeline-vertical .qx-timeline-item', itemSpacing, 'padding-bottom', 'px') }} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-item:last-child', 'padding-bottom', '0') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'flex', '0 0 auto') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'min-width', '0') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'padding-bottom', '0') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'display', 'flex') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'flex-direction', 'column') }} + +{# Timeline Marker #} +{% if showMarkers %} +{{ style.css(id ~ ' .qx-timeline-marker', 'position', 'absolute') }} +{{ style.css(id ~ ' .qx-timeline-marker', 'display', 'flex') }} +{{ style.css(id ~ ' .qx-timeline-marker', 'align-items', 'center') }} +{{ style.css(id ~ ' .qx-timeline-marker', 'justify-content', 'center') }} +{{ style.css(id ~ ' .qx-timeline-marker', 'z-index', '2') }} +{{ style.css(id ~ ' .qx-timeline-marker', 'width', '15px') }} +{{ style.css(id ~ ' .qx-timeline-marker', 'height', '15px') }} +{{ style.css(id ~ ' .qx-timeline-marker', 'top', '5px') }} +{% else %} +{{ style.css(id ~ ' .qx-timeline-marker', 'display', 'none') }} +{% endif %} + +{# Vertical Marker Position #} +{% if showMarkers %} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-marker', 'transform', 'translateX(-50%)') }} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-marker', 'top', '0') }} +{% endif %} + +{# Vertical Marker Position #} +{% if showMarkers %} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-marker', 'transform', 'translateX(-50%)') }} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-marker', 'top', '0') }} +{% endif %} + +{# Connector Position: Right Side #} +{{ style.css(id ~ '.qx-timeline-connector-pos-right .qx-timeline-vertical', 'padding-right', '0') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-right .qx-timeline-vertical', 'padding-left', '0') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-right .qx-timeline-vertical .qx-timeline-connector', 'left', 'auto') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-right .qx-timeline-vertical .qx-timeline-connector', 'right', '-0.1px') }} +{% if showMarkers %} +{{ style.css(id ~ '.qx-timeline-connector-pos-right .qx-timeline-vertical .qx-timeline-marker', 'right', '-14px') }} +{% endif %} + +{# Center Connector Position: Alternate items left/right #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical', 'padding-left', '0') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical', 'padding-right', '0') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-connector', 'left', '50%') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-connector', 'transform', 'translateX(-50%)') }} + +{# Center layout: two-column structure #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item', 'width', '50%') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item', 'clear', 'none') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(even)', 'float', 'left') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(even)', 'margin-right', '1px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(odd)', 'float', 'right') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(odd)', 'clear', 'right') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical::after', 'content', '""') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical::after', 'display', 'table') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical::after', 'clear', 'both') }} + +{# Center marker placement #} +{% if showMarkers %} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(even) .qx-timeline-marker', 'left', 'auto') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(even) .qx-timeline-marker', 'right', '-7.5px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(even) .qx-timeline-marker', 'transform', 'none') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(odd) .qx-timeline-marker', 'left', '-7.5px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(odd) .qx-timeline-marker', 'transform', 'none') }} +{% endif %} + +{# Center content alignment #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(even) .qx-timeline-content', 'text-align', 'right') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(even) .qx-timeline-content', 'margin-right', '45px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(even) .qx-timeline-content', 'margin-left', '0') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(odd) .qx-timeline-content', 'text-align', 'left') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(odd) .qx-timeline-content', 'margin-left', '45px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(odd) .qx-timeline-content', 'margin-right', '0') }} + +{# Center image alignment #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(even) .qx-timeline-image', 'display', 'flex') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(even) .qx-timeline-image', 'justify-content', 'flex-end') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(odd) .qx-timeline-image', 'justify-content', 'flex-start') }} + +{# Horizontal Marker Position #} +{% if showMarkers %} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-marker', 'top', '-52px') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-marker', 'left', '50%') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-marker', 'transform', 'translateX(-50%)') }} +{% endif %} + +{# Arrow Indicators #} +{% if showArrows %} +{# Base arrow styles #} +{{ style.css(id ~ ' .qx-timeline-arrow', 'position', 'absolute') }} +{{ style.css(id ~ ' .qx-timeline-arrow', 'background-color', connectorColor) }} +{{ style.css(id ~ ' .qx-timeline-arrow', 'pointer-events', 'none') }} + +{# Vertical layout arrows - extending from dots toward content #} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-arrow', 'width', '30px') }} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-arrow', 'height', '2px') }} +{{ style.css(id ~ ' .qx-timeline-vertical .qx-timeline-arrow', 'top', '12px') }} + +{# Vertical left position arrows - extend from dot to the right toward content #} +{{ style.css(id ~ '.qx-timeline-connector-pos-left .qx-timeline-vertical .qx-timeline-arrow', 'left', '0') }} + +{# Vertical right position arrows - extend from dot to the left toward content #} +{{ style.css(id ~ '.qx-timeline-connector-pos-right .qx-timeline-vertical .qx-timeline-arrow', 'right', '0.01px') }} + +{# Vertical center position arrows - extend from dots toward content #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(odd) .qx-timeline-arrow', 'left', '0.001px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item:nth-child(even) .qx-timeline-arrow', 'right', '0.001px') }} + +{# Horizontal layout arrows - extending from dots toward content #} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-arrow', 'width', '2px') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-arrow', 'height', '30px') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-arrow', 'left', '50%') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-arrow', 'transform', 'translateX(-50%)') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-arrow', 'z-index', '-10') }} + +{# Horizontal top position arrows - extend from dot downward toward content #} +{{ style.css(id ~ '.qx-timeline-connector-pos-top .qx-timeline-horizontal .qx-timeline-arrow', 'top', '-42px') }} + +{# Horizontal bottom position arrows - extend from dot upward toward content #} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-arrow', 'bottom', '-42px') }} + +{# Horizontal center position arrows - extend from dots toward content #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(odd) .qx-timeline-arrow', 'bottom', '-42px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(even) .qx-timeline-arrow', 'top', '-42px') }} + +{# Builder mode center position arrow adjustments #} +{% if mode == 'builder' %} + +{% endif %} +{% endif %} + +{# Horizontal Connector Position: Center #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-connector', 'top', '50%') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-connector', 'transform', 'translateY(-50%)') }} + +{# Center Position Specific Overrides #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-slider-container', 'overflow-x', 'clip') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-slider-container', 'overflow-y', 'visible') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-slider-container', 'padding-top', '0') }} + +{# Keep stretch alignment for equal heights but use transforms for positioning #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-slider-track', 'align-items', 'stretch') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-slider-track', 'position', 'relative') }} + +{# Odd items: above center line #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(odd)', 'transform', 'translateY(-170px)') }} + +{# Even items: below center line #} +{% if mode == 'builder' %} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(even)', 'transform', 'translateY(177px)') }} +{% else %} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(even)', 'transform', 'translateY(170px)') }} +{% endif %} + +{# Markers positioned ON the connector line #} +{% if showMarkers %} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(odd) .qx-timeline-marker', 'top', 'auto') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(odd) .qx-timeline-marker', 'bottom', '-50px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(even) .qx-timeline-marker', 'top', '-50px') }} +{% endif %} + +{% if mode == 'builder' and showMarkers %} +{# Builder mode center position marker fixes - these override the general styles above #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(odd)', 'transform', 'translateY(-150px)') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(odd) .qx-timeline-marker', 'bottom', '-42px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(even) .qx-timeline-marker', 'top', '-45px') }} +{% endif %} + +{# Horizontal Connector Position: Top #} +{{ style.css(id ~ '.qx-timeline-connector-pos-top .qx-timeline-horizontal .qx-timeline-connector', 'top', '12px') }} +{% if showMarkers %} +{{ style.css(id ~ '.qx-timeline-connector-pos-top .qx-timeline-horizontal .qx-timeline-marker', 'top', '-50px') }} +{% endif %} + +{# Horizontal Top Position Navigation #} +{{ style.css(id ~ '.qx-timeline-connector-pos-top .qx-timeline-horizontal .qx-timeline-nav-prev', 'left', '-13px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-top .qx-timeline-horizontal .qx-timeline-nav-prev', 'top', '-3px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-top .qx-timeline-horizontal .qx-timeline-nav-next', 'right', '-13px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-top .qx-timeline-horizontal .qx-timeline-nav-next', 'top', '-3px') }} + +{# Horizontal Center Position Navigation #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-nav-prev', 'left', '-13px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-nav-prev', 'top', '0.001px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-nav-prev', 'bottom', '0.001px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-nav-prev', 'margin', 'auto') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-nav-next', 'right', '-13px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-nav-next', 'top', '0.001px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-nav-next', 'bottom', '0.001px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-nav-next', 'margin', 'auto') }} + +{# Horizontal Connector Position: Bottom #} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-connector', 'top', 'auto') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-connector', 'bottom', '10px') }} +{% if showMarkers %} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-marker', 'top', 'auto') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-marker', 'bottom', '-55px') }} +{% endif %} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-slider-container', 'padding-top', '0px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-slider-container', 'padding-bottom', '60px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-nav-prev', 'left', '-13px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-nav-prev', 'bottom', '-5px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-nav-prev', 'top', 'unset') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-nav-next', 'right', '-13px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-nav-next', 'bottom', '-5px') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-bottom .qx-timeline-horizontal .qx-timeline-nav-next', 'top', 'unset') }} + +{# Timeline Dot (default marker) #} +{% if showMarkers %} +{{ style.css(id ~ ' .qx-timeline-dot', 'width', '15px') }} +{{ style.css(id ~ ' .qx-timeline-dot', 'height', '15px') }} +{{ style.css(id ~ ' .qx-timeline-dot', 'border-radius', '50%') }} +{{ style.css(id ~ ' .qx-timeline-dot', 'background-color', connectorColor) }} +{% endif %} + +{# Icon Styling #} + +{# Timeline Content #} +{{ style.css(id ~ ' .qx-timeline-content', 'position', 'relative') }} +{{ style.background(id ~ ' .qx-timeline-content', itemBg) }} +{{ style.border(id ~ ' .qx-timeline-content', itemBorder) }} +{{ style.padding(id ~ ' .qx-timeline-content', itemPadding) }} +{{ style.borderRadius(id ~ ' .qx-timeline-content', itemBorderRadius) }} +{{ style.boxShadow(id ~ ' .qx-timeline-content', itemShadow) }} + +{# Make horizontal timeline content fill full height #} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-content', 'height', '100%') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-content', 'display', 'flex') }} +{{ style.css(id ~ ' .qx-timeline-horizontal .qx-timeline-content', 'flex-direction', 'column') }} + + + +{# Content vertical alignment for horizontal layout #} +{% set contentAlignment = general.layout_settings.content_vertical_alignment %} + +{# Always generate all alignment classes for real-time builder updates #} +{{ style.css(id ~ '.qx-timeline-content-align-top.qx-timeline-horizontal .qx-timeline-content', 'justify-content', 'flex-start') }} +{{ style.css(id ~ '.qx-timeline-content-align-top .qx-timeline-horizontal .qx-timeline-content', 'justify-content', 'flex-start') }} + +{# Center alignment #} +{{ style.css(id ~ '.qx-timeline-content-align-center.qx-timeline-horizontal .qx-timeline-content', 'justify-content', 'center') }} +{{ style.css(id ~ '.qx-timeline-content-align-center .qx-timeline-horizontal .qx-timeline-content', 'justify-content', 'center') }} + +{# Bottom alignment #} +{{ style.css(id ~ '.qx-timeline-content-align-bottom.qx-timeline-horizontal .qx-timeline-content', 'justify-content', 'flex-end') }} +{{ style.css(id ~ '.qx-timeline-content-align-bottom .qx-timeline-horizontal .qx-timeline-content', 'justify-content', 'flex-end') }} + +{# Default content alignment based on connector position when no specific alignment is set #} +{{ style.css(id ~ '.qx-timeline-connector-pos-top .qx-timeline-horizontal .qx-timeline-content', 'justify-content', 'flex-start') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(odd) .qx-timeline-content', 'justify-content', 'center') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-horizontal .qx-timeline-item:nth-child(even) .qx-timeline-content', 'justify-content', 'center') }} + +{# Content alignment overrides #} +{{ style.css(id ~ '.qx-timeline-content-align-top .qx-timeline-horizontal .qx-timeline-item .qx-timeline-content', 'justify-content', 'flex-start') }} +{{ style.css(id ~ '.qx-timeline-content-align-center .qx-timeline-horizontal .qx-timeline-item .qx-timeline-content', 'justify-content', 'center') }} +{{ style.css(id ~ '.qx-timeline-content-align-bottom .qx-timeline-horizontal .qx-timeline-item .qx-timeline-content', 'justify-content', 'flex-end') }} + +{# Timeline Date #} +{{ style.css(id ~ ' .qx-timeline-date', 'color', dateColor) }} +{{ style.css(id ~ ' .qx-timeline-date', 'margin-bottom', '8px') }} +{{ style.css(id ~ ' .qx-timeline-date', 'font-size', '14px') }} +{{ style.css(id ~ ' .qx-timeline-date', 'font-weight', '500') }} +{{ style.typography(id ~ ' .qx-timeline-date', dateFont) }} + +{# Timeline Title #} +{{ style.css(id ~ ' .qx-timeline-title', 'color', titleColor) }} +{{ style.css(id ~ ' .qx-timeline-title', 'margin-bottom', '0') }} +{{ style.css(id ~ ' .qx-timeline-title', 'margin-top', '0') }} +{{ style.typography(id ~ ' .qx-timeline-title', titleFont) }} +{{ style.css(id ~ ' .qx-timeline-title a', 'color', 'inherit') }} +{{ style.css(id ~ ' .qx-timeline-title a:hover', 'color', 'inherit') }} +{{ style.css(id ~ ' .qx-timeline-title a', 'text-decoration', 'none') }} + +{# Timeline Image #} +{{ style.css(id ~ ' .qx-timeline-image', 'margin-bottom', '15px') }} +{{ style.css(id ~ ' .qx-timeline-image img', 'max-width', '100%') }} +{{ style.css(id ~ ' .qx-timeline-image img', 'height', 'auto') }} +{{ style.css(id ~ ' .qx-timeline-image img', 'border-radius', '4px') }} + +{# Timeline Description #} +{{ style.css(id ~ ' .qx-timeline-description', 'color', descriptionColor) }} +{{ style.css(id ~ ' .qx-timeline-description', 'margin-bottom', '0') }} +{{ style.typography(id ~ ' .qx-timeline-description', descriptionFont) }} +{{ style.css(id ~ ' .qx-timeline-description p:last-child', 'margin-bottom', '0') }} + +{# Active Item Styling #} +{% if showMarkers %} +{{ style.css(id ~ ' .qx-timeline-item-active .qx-timeline-marker', 'transform', 'translateX(-50%) scale(1.4)') }} +{{ style.css(id ~ ' .qx-timeline-item-active .qx-timeline-dot', 'background-color', connectorColor) }} + +{# Active Item Styling for Center Position #} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item-active:nth-child(even) .qx-timeline-marker', 'transform', 'scale(1.4)') }} +{{ style.css(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item-active:nth-child(odd) .qx-timeline-marker', 'transform', 'scale(1.4)') }} +{% endif %} + +{# Hover Effects #} +{% if enableHover %} + {{ style.css(id ~ ' .qx-timeline-item', 'transition', 'all 0.3s ease') }} + + {% if hoverItemBg %} + {{ style.background(id ~ ' .qx-timeline-item:hover .qx-timeline-content', hoverItemBg) }} + {% endif %} + + {% if hoverTitleColor %} + {{ style.css(id ~ ' .qx-timeline-item:hover .qx-timeline-title', 'color', hoverTitleColor) }} + {% endif %} + + {% if hoverTitleFont %} + {{ style.typography(id ~ ' .qx-timeline-item:hover .qx-timeline-title', hoverTitleFont) }} + {% endif %} + + {% if hoverDateColor %} + {{ style.css(id ~ ' .qx-timeline-item:hover .qx-timeline-date', 'color', hoverDateColor) }} + {% endif %} + + {% if hoverDateFont %} + {{ style.typography(id ~ ' .qx-timeline-item:hover .qx-timeline-date', hoverDateFont) }} + {% endif %} + + {% if hoverDescriptionColor %} + {{ style.css(id ~ ' .qx-timeline-item:hover .qx-timeline-description', 'color', hoverDescriptionColor) }} + {% endif %} + + {% if hoverDescriptionFont %} + {{ style.typography(id ~ ' .qx-timeline-item:hover .qx-timeline-description', hoverDescriptionFont) }} + {% endif %} +{% endif %} + +{# Responsive Design #} +{% if hideOnMobile %} + {# Hide entire timeline on mobile when hideOnMobile is enabled #} + {{ style.phone(id ~ ' .qx-timeline-wrapper', 'display: none') }} +{% else %} + {# Mobile layout adjustments when timeline is visible #} + {% if mobileLayout == 'vertical' %} + {# Force vertical layout on mobile #} + {{ style.phone(id ~ ' .qx-timeline-horizontal', 'flex-direction: column') }} + {{ style.phone(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'margin-right: 0') }} + {{ style.phone(id ~ ' .qx-timeline-horizontal .qx-timeline-item', 'margin-bottom: ' ~ (itemSpacing.mobile ?? itemSpacing.value ?? itemSpacing ?: 20) ~ 'px') }} + + {# Vertical layout mobile optimizations #} + {{ style.phone(id ~ ' .qx-timeline-vertical', 'padding-left: 40px') }} + {{ style.phone(id ~ ' .qx-timeline-vertical .qx-timeline-marker', 'left: -40px') }} + {{ style.phone(id ~ ' .qx-timeline-vertical .qx-timeline-connector', 'left: 10px') }} + + {# Center connector mobile adjustments #} + {{ style.phone(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item', 'width: 100%') }} + {{ style.phone(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item', 'float: none') }} + {{ style.phone(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item', 'clear: both') }} + {{ style.phone(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item .qx-timeline-marker', 'left: -40px') }} + {{ style.phone(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item .qx-timeline-marker', 'right: auto') }} + {{ style.phone(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item .qx-timeline-content', 'text-align: left') }} + {{ style.phone(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item .qx-timeline-content', 'margin-left: 45px') }} + {{ style.phone(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-item .qx-timeline-content', 'margin-right: 0') }} + {{ style.phone(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-connector', 'left: 10px') }} + {{ style.phone(id ~ '.qx-timeline-connector-pos-center .qx-timeline-vertical .qx-timeline-connector', 'transform: none') }} + + {% elseif mobileLayout == 'horizontal' %} + {# Keep horizontal layout on mobile but optimize #} + {{ style.phone(id ~ ' .qx-timeline-horizontal .qx-timeline-marker', 'top: -30px') }} + {{ style.phone(id ~ ' .qx-timeline-horizontal .qx-timeline-marker', 'left: 50%') }} + {{ style.phone(id ~ ' .qx-timeline-horizontal .qx-timeline-marker', 'transform: translateX(-50%)') }} + {{ style.phone(id ~ ' .qx-timeline-horizontal .qx-timeline-connector', 'display: block') }} + {{ style.phone(id ~ ' .qx-timeline-horizontal .qx-timeline-connector', 'top: 0') }} + {{ style.phone(id ~ ' .qx-timeline-horizontal .qx-timeline-connector', 'height: 2px') }} + {{ style.phone(id ~ ' .qx-timeline-horizontal .qx-timeline-connector', 'width: 100%') }} + {% endif %} +{% endif %} + +{# Placeholder Styling #} +{{ style.css(id ~ ' .qx-timeline-placeholder', 'text-align', 'center') }} +{{ style.css(id ~ ' .qx-timeline-placeholder', 'padding', '40px') }} +{{ style.css(id ~ ' .qx-timeline-placeholder', 'color', '#999') }} +{{ style.css(id ~ ' .qx-timeline-placeholder p', 'margin', '0') }} + +{# Remove entry animation #} +{{ style.css(id ~ ' .qx-timeline-item', 'opacity', '1') }} +{{ style.css(id ~ ' .qx-timeline-item', 'transform', 'none') }} +{{ style.css(id ~ ' .qx-timeline-item', 'transition', 'none') }} + +{{ style.load(advanced.identifier.id) }}