Skip to content

Instantly share code, notes, and snippets.

@Tronquin
Created March 11, 2022 22:57
Show Gist options
  • Save Tronquin/3c05607abbe3277833c2223d0eda3d57 to your computer and use it in GitHub Desktop.
Save Tronquin/3c05607abbe3277833c2223d0eda3d57 to your computer and use it in GitHub Desktop.
Dynamic Freeshipping Bar Shopify (Liquid, Javascript, CSS)
.fsb {
background-color: var(--bg-color);
color: var(--color);
font-size: 15px;
height: 4em;
}
.fsb .fsb-progress {
display: flex;
padding: 1em;
align-items: center;
justify-content: center;
text-align: center;
height: 100%;
position: relative;
}
.fsb .fsb-progress p {
font-size: 1em;
text-transform: uppercase;
letter-spacing: 0.1em;
margin: 0;
position: relative;
z-index: 2;
}
.fsb .fsb-progress p .fsb--number {
color: var(--accent-color);
font-weight: bold;
}
.fsb .fsb-progress::before {
content: "";
width: var(--progress);
background-color: var(--progress-color);
position: absolute;
left: 0;
height: 100%;
transition: width 0.75s ease-in-out;
z-index: 1;
}
class Fsb {
constructor(fsb = { selector: '#fsb', events: [], placeholder: '(x)' }) {
if (fsb.selector && typeof fsb.selector == 'string' && fsb.selector !== '') {
this.selector = fsb.selector;
} else {
throw new TypeError("Please pass a valid selector");
}
this.fsbElement = document.querySelector(this.selector);
if(!this.fsbElement) {
throw new TypeError("Freeshipping Bar Element Not Found");
}
this.events = fsb.events;
this.placeholder = fsb.placeholder;
this.goal = parseInt(this.fsbElement.dataset.goal);
this.startHeadline = this.fsbElement.dataset.headlineStart;
this.middleHeadline = this.fsbElement.dataset.headlineMiddle;
this.endHeadline = this.fsbElement.dataset.headlineEnd;
}
getCart() {
return fetch('/cart.js')
.then(res=>res.json())
}
update(cart) {
let shipping = {
difference: this.goal - cart.total_price,
progress: Math.round((cart.total_price * 100) / this.goal)
}
if(cart.total_price <= 0) {
this.fsbElement.style.setProperty('--progress', `${shipping.progress}%`);
this.fsbElement.querySelector('.fsb-paragraph').innerHTML = this.startHeadline.replace(this.placeholder, `<span class="fsb--number">${this.formatMoney(this.goal)}</span>`);
} else if(cart.total_price > 0 && cart.total_price < this.goal) {
this.fsbElement.style.setProperty('--progress', `${shipping.progress}%`);
this.fsbElement.querySelector('.fsb-paragraph').innerHTML = this.middleHeadline.replace(this.placeholder, `<span class="fsb--number">${this.formatMoney(shipping.difference)}</span>`);
} else if(cart.total_price >= this.goal) {
this.fsbElement.style.setProperty('--progress', `${shipping.progress}%`);
this.fsbElement.querySelector('.fsb-paragraph').innerHTML = this.endHeadline.replace(this.placeholder, `<span class="fsb--number">${this.formatMoney(this.goal)}</span>`);
}
}
attachEvents() {
if(this.events.length > 0) {
this.events.forEach(event => {
document.addEventListener(event, e => this.getCart().then(cart => this.update(cart)), true);
})
}
}
formatMoney(cents, format) {
if (typeof cents == 'string') { cents = cents.replace('.',''); }
var value = '';
var placeholderRegex = /\{\{\s*(\w+)\s*\}\}/;
var formatString = (format || "${{amount_no_decimals}}");
function defaultOption(opt, def) {
return (typeof opt == 'undefined' ? def : opt);
}
function formatWithDelimiters(number, precision, thousands, decimal) {
precision = defaultOption(precision, 2);
thousands = defaultOption(thousands, ',');
decimal = defaultOption(decimal, '.');
if (isNaN(number) || number == null) { return 0; }
number = (number/100.0).toFixed(precision);
var parts = number.split('.'),
dollars = parts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + thousands),
cents = parts[1] ? (decimal + parts[1]) : '';
return dollars + cents;
}
switch(formatString.match(placeholderRegex)[1]) {
case 'amount':
value = formatWithDelimiters(cents, 2);
break;
case 'amount_no_decimals':
value = formatWithDelimiters(cents, 0);
break;
case 'amount_with_comma_separator':
value = formatWithDelimiters(cents, 2, '.', ',');
break;
case 'amount_no_decimals_with_comma_separator':
value = formatWithDelimiters(cents, 0, '.', ',');
break;
}
return formatString.replace(placeholderRegex, value);
}
}
{% assign freeShipping = settings.fsb_goal | times: 100 %}
{% assign totalPrice = cart.total_price %}
{% assign shippingDifference = freeShipping | minus: totalPrice %}
{% assign shippingDifferencePercentage = shippingDifference | divided_by: 100 %}
{% assign shippingProgress = totalPrice | times:100 | divided_by:freeShipping | append:'%' %}
{% assign initial_message = settings.fsb_headline_start %}
{% assign middle_message = settings.fsb_headline_middle %}
{% assign end_message = settings.fsb_headline_end %}
{% assign shippingGoalWithCurrency = freeShipping | money_without_trailing_zeros | prepend:'<span class="fsb--number">'| append:'</span>' %}
{% assign shippingDifferenceWithCurrency = shippingDifference | money_without_trailing_zeros | prepend:'<span class="fsb--number">'| append:'</span>' %}
<div id="fsb" class="fsb" style="--bg-color: {{settings.fsb_background_color}};
--progress-color: {{settings.fsb_progress_color}};
--color: {{settings.fsb_text_color}};
--accent-color: {{settings.fsb_accent_color}};
--progress: {{shippingProgress}};
"
data-headline-start="{{settings.fsb_headline_start}}"
data-headline-middle="{{settings.fsb_headline_middle}}"
data-headline-end="{{settings.fsb_headline_end}}"
data-goal="{{freeShipping}}">
<div class="fsb-progress">
{% if cart.total_price <= 0 %}
<p class="fsb-paragraph">
{{ initial_message | replace: "(x)", shippingGoalWithCurrency }}
</p>
{% elsif cart.total_price > 0 and cart.total_price < freeShipping %}
<p class="fsb-paragraph">
{{ middle_message | replace: '(x)', shippingDifferenceWithCurrency }}
</p>
{% elsif cart.total_price >= freeShipping %}
<p class="fsb-paragraph">
{{ end_message | replace: "(x)", shippingGoalWithCurrency }}
</p>
{% endif %}
</div>
</div>
{
"name": "Freeshipping Bar",
"settings": [
{
"type": "checkbox",
"id": "fsb_enable",
"label": "Enable/Disable Free Shipping Bar",
"default": true
},
{
"type": "checkbox",
"id": "fsb_ajax",
"label": "Enable/Disable Ajax Functionality",
"default": true
},
{
"type": "header",
"content": "Goal"
},
{
"type": "range",
"id": "fsb_goal",
"min": 1,
"max": 100,
"step": 1,
"unit": "$",
"label": "Goal",
"default": 5
},
{
"type": "header",
"content": "Headline Steps"
},
{
"type": "text",
"id": "fsb_headline_start",
"label": "Start Headline",
"default": "If you add (x) worth of products to your cart, you'll get Freeshipping!",
"info": "Use the special character '(x)' as a placeholder for the 'Goal' amount"
},
{
"type": "text",
"id": "fsb_headline_middle",
"label": "Middle Headline",
"default": "You are (x) away from Freeshipping!",
"info": "Use the special character '(x)' as a placeholder for the 'Remaining' amount"
},
{
"type": "text",
"id": "fsb_headline_end",
"label": "End Headline",
"default": "You have Freeshipping!",
"info": "Use the special character '(x)' as a placeholder for the 'Goal' amount"
},
{
"type": "header",
"content": "Colors"
},
{
"type": "color",
"id": "fsb_background_color",
"label": "Background Color",
"default": "#000000"
},
{
"type": "color",
"id": "fsb_progress_color",
"label": "Progress Bar Color",
"default": "#006fbb"
},
{
"type": "color",
"id": "fsb_text_color",
"label": "Text Color",
"default": "#FFFFFF"
},
{
"type": "color",
"id": "fsb_accent_color",
"label": "Accent Color",
"default": "#c03"
}
]
}
//ADD THIS BEFORE </head>
{% if settings.fsb_enable %}
{{ 'hc-freeshipping-bar.css' | asset_url | stylesheet_tag }}
{% if settings.fsb_ajax %}
{{ 'hc-freeshipping-bar.js' | asset_url | script_tag }}
<script>
document.addEventListener('DOMContentLoaded', function() {
const freeshippingBar = new HCFsb({
selector: '#hc-fsb', // Selector of the HTML template (Snippet)
events: ['fsb:product:added', 'fsb:cart:update'], //Events used to update the FSB
placeholder: '(x)' //Placeholder character to replace the goal/remaining amount in the FSB headline
});
freeshippingBar.attachEvents();
});
</script>
{% endif %}
{% endif %}
//ADD THIS WHEREVER YOU WANT THE FSB TO APPEAR
{% if settings.fsb_enable %}
{% render 'hc-freeshipping-bar' %}
{% endif %}
@victorchtb
Copy link

Hi the Json script can't be saved, How can i do pls ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment