Create a new section file called story-timeline.liquid and add the following code:
Show Code {% assign wbs_id = block.id | replace: '_', '' | downcase %} {% style %} .wbs-journey-map-{{ wbs_id }} { padding: 60px 20px; background-color: {{ section.settings.background_color }}; overflow: hidden; } .wbs-journey-map__heading-{{ wbs_id }} { text-align: center; margin-bottom: 20px; color: {{ section.settings.text_color }}; font-size: {{ section.settings.heading_size }}px; } .wbs-journey-map__subheading-{{ wbs_id }} { text-align: center; margin-bottom: 60px; color: {{ section.settings.subtext_color }}; font-size: {{ section.settings.subheading_size }}px; max-width: 600px; margin-left: auto; margin-right: auto; } .wbs-journey-map__container-{{ wbs_id }} { max-width: {{ section.settings.max_width }}px; margin: 0 auto; position: relative; } .wbs-journey-map__timeline-{{ wbs_id }} { position: relative; padding: 40px 0; } .wbs-journey-map__line-{{ wbs_id }} { position: absolute; top: 0; left: 50%; transform: translateX(-50%); width: 4px; height: 100%; background: linear-gradient(to bottom, {{ section.settings.timeline_start_color }}, {{ section.settings.timeline_end_color }}); border-radius: 2px; } @media screen and (max-width: 768px) { .wbs-journey-map__line-{{ wbs_id }} { left: 30px; } } .wbs-journey-map__stage-{{ wbs_id }} { position: relative; margin-bottom: 80px; opacity: 0; transform: translateY(30px); transition: all 0.6s ease; } .wbs-journey-map__stage-{{ wbs_id }}.visible { opacity: 1; transform: translateY(0); } .wbs-journey-map__stage-{{ wbs_id }}:last-child { margin-bottom: 0; } .wbs-journey-map__stage-content-{{ wbs_id }} { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center; } @media screen and (max-width: 768px) { .wbs-journey-map__stage-content-{{ wbs_id }} { grid-template-columns: 1fr; gap: 20px; padding-left: 80px; } } .wbs-journey-map__stage-{{ wbs_id }}:nth-child(even) .wbs-journey-map__stage-content-{{ wbs_id }} { direction: rtl; } .wbs-journey-map__stage-{{ wbs_id }}:nth-child(even) .wbs-journey-map__stage-text-{{ wbs_id }}, .wbs-journey-map__stage-{{ wbs_id }}:nth-child(even) .wbs-journey-map__stage-image-{{ wbs_id }} { direction: ltr; } @media screen and (max-width: 768px) { .wbs-journey-map__stage-{{ wbs_id }}:nth-child(even) .wbs-journey-map__stage-content-{{ wbs_id }} { direction: ltr; } } .wbs-journey-map__stage-marker-{{ wbs_id }} { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: {{ section.settings.marker_size }}px; height: {{ section.settings.marker_size }}px; background-color: {{ section.settings.marker_color }}; border: 4px solid {{ section.settings.background_color }}; border-radius: 50%; z-index: 2; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 8px {{ section.settings.marker_ring_color }}; } @media screen and (max-width: 768px) { .wbs-journey-map__stage-marker-{{ wbs_id }} { left: 30px; } } .wbs-journey-map__stage-marker-{{ wbs_id }} svg { width: 50%; height: 50%; color: {{ section.settings.marker_icon_color }}; } .wbs-journey-map__stage-number-{{ wbs_id }} { font-size: 18px; font-weight: 700; color: {{ section.settings.marker_icon_color }}; } .wbs-journey-map__stage-text-{{ wbs_id }} { padding: 30px; background-color: {{ section.settings.card_background }}; border-radius: {{ section.settings.card_border_radius }}px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); transition: all 0.3s ease; } .wbs-journey-map__stage-text-{{ wbs_id }}:hover { transform: translateY(-5px); box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15); } .wbs-journey-map__stage-label-{{ wbs_id }} { display: inline-block; padding: 6px 16px; background-color: {{ section.settings.label_background }}; color: {{ section.settings.label_text_color }}; border-radius: 20px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 15px; } .wbs-journey-map__stage-title-{{ wbs_id }} { font-size: 28px; font-weight: 700; margin-bottom: 15px; color: {{ section.settings.text_color }}; } .wbs-journey-map__stage-description-{{ wbs_id }} { font-size: 16px; line-height: 1.6; color: {{ section.settings.subtext_color }}; } .wbs-journey-map__stage-image-{{ wbs_id }} { position: relative; border-radius: {{ section.settings.image_border_radius }}px; overflow: hidden; aspect-ratio: {{ section.settings.image_aspect_ratio }}; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); } .wbs-journey-map__stage-image-{{ wbs_id }} img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.5s ease; } .wbs-journey-map__stage-image-{{ wbs_id }}:hover img { transform: scale(1.05); } .wbs-journey-map__stage-image-placeholder-{{ wbs_id }} { width: 100%; height: 100%; background-color: #f4f4f4; display: flex; align-items: center; justify-content: center; } .wbs-journey-map__stage-image-placeholder-{{ wbs_id }} svg { width: 80px; height: 80px; opacity: 0.3; } .wbs-journey-map__cta-{{ wbs_id }} { text-align: center; margin-top: 60px; } .wbs-journey-map__cta-button-{{ wbs_id }} { display: inline-block; padding: 16px 40px; background-color: {{ section.settings.button_color }}; color: {{ section.settings.button_text_color }}; text-decoration: none; border-radius: {{ section.settings.button_border_radius }}px; font-size: 18px; font-weight: 600; transition: all 0.3s ease; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); } .wbs-journey-map__cta-button-{{ wbs_id }}:hover { background-color: {{ section.settings.button_hover_color }}; transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); } .wbs-journey-map__empty-state-{{ wbs_id }} { text-align: center; padding: 80px 20px; color: {{ section.settings.subtext_color }}; } .wbs-journey-map__empty-state-{{ wbs_id }} svg { width: 100px; height: 100px; margin-bottom: 20px; opacity: 0.3; } {% endstyle %} <wbs-journey-map-{{ wbs_id }} class="wbs-journey-map-{{ wbs_id }}" {{ section.shopify_attributes }}> {% if section.settings.heading != blank %} <h2 class="wbs-journey-map__heading-{{ wbs_id }}">{{ section.settings.heading }}</h2> {% endif %} {% if section.settings.subheading != blank %} <div class="wbs-journey-map__subheading-{{ wbs_id }}">{{ section.settings.subheading }}</div> {% endif %} <div class="wbs-journey-map__container-{{ wbs_id }}"> {% assign has_stages = false %} {% for i in (1..6) %} {% assign title_key = 'stage_' | append: i | append: '_title' %} {% if section.settings[title_key] != blank %} {% assign has_stages = true %} {% break %} {% endif %} {% endfor %} {% if has_stages %} <div class="wbs-journey-map__timeline-{{ wbs_id }}"> <div class="wbs-journey-map__line-{{ wbs_id }}"></div> {% for i in (1..6) %} {% assign title_key = 'stage_' | append: i | append: '_title' %} {% assign label_key = 'stage_' | append: i | append: '_label' %} {% assign description_key = 'stage_' | append: i | append: '_description' %} {% assign image_key = 'stage_' | append: i | append: '_image' %} {% assign icon_key = 'stage_' | append: i | append: '_icon' %} {% if section.settings[title_key] != blank %} <div class="wbs-journey-map__stage-{{ wbs_id }}" data-stage> <div class="wbs-journey-map__stage-marker-{{ wbs_id }}"> {% if section.settings[icon_key] == 'number' %} <span class="wbs-journey-map__stage-number-{{ wbs_id }}">{{ i }}</span> {% elsif section.settings[icon_key] == 'lightbulb' %} <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" /> </svg> {% elsif section.settings[icon_key] == 'pencil' %} <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" /> </svg> {% elsif section.settings[icon_key] == 'cube' %} <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" /> </svg> {% elsif section.settings[icon_key] == 'gift' %} <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v13m0-13V6a2 2 0 112 2h-2zm0 0V5.5A2.5 2.5 0 109.5 8H12zm-7 4h14M5 12a2 2 0 110-4h14a2 2 0 110 4M5 12v7a2 2 0 002 2h10a2 2 0 002-2v-7" /> </svg> {% elsif section.settings[icon_key] == 'truck' %} <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16V6a1 1 0 00-1-1H4a1 1 0 00-1 1v10a1 1 0 001 1h1m8-1a1 1 0 01-1 1H9m4-1V8a1 1 0 011-1h2.586a1 1 0 01.707.293l3.414 3.414a1 1 0 01.293.707V16a1 1 0 01-1 1h-1m-6-1a1 1 0 001 1h1M5 17a2 2 0 104 0m-4 0a2 2 0 114 0m6 0a2 2 0 104 0m-4 0a2 2 0 114 0" /> </svg> {% elsif section.settings[icon_key] == 'heart' %} <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" /> </svg> {% else %} <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" /> </svg> {% endif %} </div> <div class="wbs-journey-map__stage-content-{{ wbs_id }}"> <div class="wbs-journey-map__stage-text-{{ wbs_id }}"> {% if section.settings[label_key] != blank %} <span class="wbs-journey-map__stage-label-{{ wbs_id }}">{{ section.settings[label_key] }}</span> {% endif %} <h3 class="wbs-journey-map__stage-title-{{ wbs_id }}">{{ section.settings[title_key] }}</h3> {% if section.settings[description_key] != blank %} <div class="wbs-journey-map__stage-description-{{ wbs_id }}">{{ section.settings[description_key] }}</div> {% endif %} </div> <div class="wbs-journey-map__stage-image-{{ wbs_id }}"> {% if section.settings[image_key] != blank %} <img src="{{ section.settings[image_key] | image_url: width: 800 }}" alt="{{ section.settings[image_key].alt | escape }}" loading="lazy" width="{{ section.settings[image_key].width }}" height="{{ section.settings[image_key].height }}" > {% else %} <div class="wbs-journey-map__stage-image-placeholder-{{ wbs_id }}"> {{ 'image' | placeholder_svg_tag }} </div> {% endif %} </div> </div> </div> {% endif %} {% endfor %} </div> {% if section.settings.show_cta and section.settings.cta_text != blank %} <div class="wbs-journey-map__cta-{{ wbs_id }}"> <a href="{{ section.settings.cta_link }}" class="wbs-journey-map__cta-button-{{ wbs_id }}"> {{ section.settings.cta_text }} </a> </div> {% endif %} {% else %} <div class="wbs-journey-map__empty-state-{{ wbs_id }}"> {{ 'image' | placeholder_svg_tag }} <p>{{ section.settings.empty_state_text }}</p> </div> {% endif %} </div> </wbs-journey-map-{{ wbs_id }}> <script> (function() { class JourneyMap{{ wbs_id }} extends HTMLElement { constructor() { super(); this.stages = this.querySelectorAll('[data-stage]'); this.observerOptions = { threshold: 0.2, rootMargin: '0px 0px -100px 0px' }; } connectedCallback() { this.setupIntersectionObserver(); } setupIntersectionObserver() { const observer = new IntersectionObserver((entries) => { entries.forEach((entry, index) => { if (entry.isIntersecting) { setTimeout(() => { entry.target.classList.add('visible'); }, index * {{ section.settings.animation_delay }}); observer.unobserve(entry.target); } }); }, this.observerOptions); this.stages.forEach(stage => { observer.observe(stage); }); } } customElements.define('wbs-journey-map-{{ wbs_id }}', JourneyMap{{ wbs_id }}); })(); </script> {% schema %} { "name": "Story Timeline", "settings": [ { "type": "header", "content": "Content" }, { "type": "inline_richtext", "id": "heading", "label": "Heading", "default": "Our Product Journey" }, { "type": "richtext", "id": "subheading", "label": "Subheading", "default": "<p>Discover the story behind every product we create</p>" }, { "type": "inline_richtext", "id": "empty_state_text", "label": "Empty state text", "default": "Add stages to create your product journey" }, { "type": "header", "content": "Stage 1" }, { "type": "inline_richtext", "id": "stage_1_label", "label": "Label", "default": "Step 1" }, { "type": "inline_richtext", "id": "stage_1_title", "label": "Title", "default": "Idea" }, { "type": "richtext", "id": "stage_1_description", "label": "Description", "default": "<p>Every great product starts with a spark of inspiration and a vision to create something meaningful.</p>" }, { "type": "image_picker", "id": "stage_1_image", "label": "Image" }, { "type": "select", "id": "stage_1_icon", "label": "Icon", "options": [ { "value": "number", "label": "Number" }, { "value": "lightbulb", "label": "Lightbulb" }, { "value": "pencil", "label": "Pencil" }, { "value": "cube", "label": "Cube" }, { "value": "gift", "label": "Gift" }, { "value": "truck", "label": "Truck" }, { "value": "heart", "label": "Heart" }, { "value": "check", "label": "Check" } ], "default": "lightbulb" }, { "type": "header", "content": "Stage 2" }, { "type": "inline_richtext", "id": "stage_2_label", "label": "Label", "default": "Step 2" }, { "type": "inline_richtext", "id": "stage_2_title", "label": "Title", "default": "Design" }, { "type": "richtext", "id": "stage_2_description", "label": "Description", "default": "<p>Our talented designers bring ideas to life with careful attention to detail and aesthetics.</p>" }, { "type": "image_picker", "id": "stage_2_image", "label": "Image" }, { "type": "select", "id": "stage_2_icon", "label": "Icon", "options": [ { "value": "number", "label": "Number" }, { "value": "lightbulb", "label": "Lightbulb" }, { "value": "pencil", "label": "Pencil" }, { "value": "cube", "label": "Cube" }, { "value": "gift", "label": "Gift" }, { "value": "truck", "label": "Truck" }, { "value": "heart", "label": "Heart" }, { "value": "check", "label": "Check" } ], "default": "pencil" }, { "type": "header", "content": "Stage 3" }, { "type": "inline_richtext", "id": "stage_3_label", "label": "Label", "default": "Step 3" }, { "type": "inline_richtext", "id": "stage_3_title", "label": "Title", "default": "Production" }, { "type": "richtext", "id": "stage_3_description", "label": "Description", "default": "<p>Quality craftsmanship meets modern manufacturing to create products that last.</p>" }, { "type": "image_picker", "id": "stage_3_image", "label": "Image" }, { "type": "select", "id": "stage_3_icon", "label": "Icon", "options": [ { "value": "number", "label": "Number" }, { "value": "lightbulb", "label": "Lightbulb" }, { "value": "pencil", "label": "Pencil" }, { "value": "cube", "label": "Cube" }, { "value": "gift", "label": "Gift" }, { "value": "truck", "label": "Truck" }, { "value": "heart", "label": "Heart" }, { "value": "check", "label": "Check" } ], "default": "cube" }, { "type": "header", "content": "Stage 4" }, { "type": "inline_richtext", "id": "stage_4_label", "label": "Label", "default": "Step 4" }, { "type": "inline_richtext", "id": "stage_4_title", "label": "Title", "default": "Packaging" }, { "type": "richtext", "id": "stage_4_description", "label": "Description", "default": "<p>Thoughtfully packaged with sustainability in mind, ready to delight from the moment you receive it.</p>" }, { "type": "image_picker", "id": "stage_4_image", "label": "Image" }, { "type": "select", "id": "stage_4_icon", "label": "Icon", "options": [ { "value": "number", "label": "Number" }, { "value": "lightbulb", "label": "Lightbulb" }, { "value": "pencil", "label": "Pencil" }, { "value": "cube", "label": "Cube" }, { "value": "gift", "label": "Gift" }, { "value": "truck", "label": "Truck" }, { "value": "heart", "label": "Heart" }, { "value": "check", "label": "Check" } ], "default": "gift" }, { "type": "header", "content": "Stage 5" }, { "type": "inline_richtext", "id": "stage_5_label", "label": "Label", "default": "Step 5" }, { "type": "inline_richtext", "id": "stage_5_title", "label": "Title", "default": "Delivery" }, { "type": "richtext", "id": "stage_5_description", "label": "Description", "default": "<p>Fast and reliable shipping ensures your product arrives safely at your doorstep.</p>" }, { "type": "image_picker", "id": "stage_5_image", "label": "Image" }, { "type": "select", "id": "stage_5_icon", "label": "Icon", "options": [ { "value": "number", "label": "Number" }, { "value": "lightbulb", "label": "Lightbulb" }, { "value": "pencil", "label": "Pencil" }, { "value": "cube", "label": "Cube" }, { "value": "gift", "label": "Gift" }, { "value": "truck", "label": "Truck" }, { "value": "heart", "label": "Heart" }, { "value": "check", "label": "Check" } ], "default": "truck" }, { "type": "header", "content": "Stage 6" }, { "type": "inline_richtext", "id": "stage_6_label", "label": "Label", "default": "Step 6" }, { "type": "inline_richtext", "id": "stage_6_title", "label": "Title", "default": "You" }, { "type": "richtext", "id": "stage_6_description", "label": "Description", "default": "<p>The final and most important step - bringing joy and value to your life every day.</p>" }, { "type": "image_picker", "id": "stage_6_image", "label": "Image" }, { "type": "select", "id": "stage_6_icon", "label": "Icon", "options": [ { "value": "number", "label": "Number" }, { "value": "lightbulb", "label": "Lightbulb" }, { "value": "pencil", "label": "Pencil" }, { "value": "cube", "label": "Cube" }, { "value": "gift", "label": "Gift" }, { "value": "truck", "label": "Truck" }, { "value": "heart", "label": "Heart" }, { "value": "check", "label": "Check" } ], "default": "heart" }, { "type": "header", "content": "Call to action" }, { "type": "checkbox", "id": "show_cta", "label": "Show button", "default": true }, { "type": "inline_richtext", "id": "cta_text", "label": "Button text", "default": "Explore Our Products" }, { "type": "url", "id": "cta_link", "label": "Button link" }, { "type": "header", "content": "Layout" }, { "type": "range", "id": "max_width", "min": 800, "max": 1400, "step": 50, "unit": "px", "label": "Maximum width", "default": 1200 }, { "type": "range", "id": "heading_size", "min": 24, "max": 56, "step": 2, "unit": "px", "label": "Heading size", "default": 40 }, { "type": "range", "id": "subheading_size", "min": 14, "max": 24, "step": 1, "unit": "px", "label": "Subheading size", "default": 18 }, { "type": "range", "id": "marker_size", "min": 40, "max": 80, "step": 5, "unit": "px", "label": "Marker size", "default": 60 }, { "type": "range", "id": "card_border_radius", "min": 0, "max": 40, "step": 2, "unit": "px", "label": "Card border radius", "default": 16 }, { "type": "range", "id": "image_border_radius", "min": 0, "max": 40, "step": 2, "unit": "px", "label": "Image border radius", "default": 12 }, { "type": "select", "id": "image_aspect_ratio", "label": "Image aspect ratio", "options": [ { "value": "1 / 1", "label": "Square (1:1)" }, { "value": "4 / 3", "label": "Landscape (4:3)" }, { "value": "16 / 9", "label": "Wide (16:9)" }, { "value": "3 / 4", "label": "Portrait (3:4)" } ], "default": "4 / 3" }, { "type": "header", "content": "Animation" }, { "type": "range", "id": "animation_delay", "min": 0, "max": 500, "step": 50, "unit": "ms", "label": "Delay between stages", "default": 150 }, { "type": "header", "content": "Colors" }, { "type": "color", "id": "background_color", "label": "Background", "default": "#ffffff" }, { "type": "color", "id": "card_background", "label": "Card background", "default": "#ffffff" }, { "type": "color", "id": "text_color", "label": "Text", "default": "#000000" }, { "type": "color", "id": "subtext_color", "label": "Subtext", "default": "#666666" }, { "type": "color", "id": "timeline_start_color", "label": "Timeline start", "default": "#a42325" }, { "type": "color", "id": "timeline_end_color", "label": "Timeline end", "default": "#780406" }, { "type": "color", "id": "marker_color", "label": "Marker background", "default": "#a42325" }, { "type": "color", "id": "marker_icon_color", "label": "Marker icon", "default": "#ffffff" }, { "type": "color", "id": "marker_ring_color", "label": "Marker ring", "default": "#f9e6e6" }, { "type": "color", "id": "label_background", "label": "Label background", "default": "#f1f1f1" }, { "type": "color", "id": "label_text_color", "label": "Label text", "default": "#666666" }, { "type": "header", "content": "Button" }, { "type": "color", "id": "button_color", "label": "Background", "default": "#a42325" }, { "type": "color", "id": "button_text_color", "label": "Text", "default": "#ffffff" }, { "type": "color", "id": "button_hover_color", "label": "Hover background", "default": "#780406" }, { "type": "range", "id": "button_border_radius", "min": 0, "max": 40, "step": 2, "unit": "px", "label": "Border radius", "default": 8 } ], "presets": [ { "name": "Story Timeline" } ] } {% endschema %} Story Timeline Shopify Section – Build a Powerful Brand Journey Experience Story Timeline Shopify Section is an effective way to visually communicate your brand’s journey, milestones, and values. Instead of presenting plain text on your About Us page, a timeline section allows you to tell your story step by step in a clean, engaging, and interactive format. This approach helps customers connect emotionally with your brand and builds long-term trust.
...