Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add floating and multifunction button #40

Merged
merged 14 commits into from
Aug 15, 2024
Empty file.
35 changes: 35 additions & 0 deletions express/blocks/floating-button/floating-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { addTempWrapperDeprecated } from '../../scripts/utils/decorate.js';
import {
createFloatingButton,
collectFloatingButtonData,
} from '../../scripts/widgets/floating-cta.js';
import { formatDynamicCartLink } from '../../scripts/utils/pricing.js';

export default function decorate(block) {
addTempWrapperDeprecated(block, 'floating-button');
if (!block.classList.contains('metadata-powered')) {
block.parentElement?.remove();
return;
}

const audience = block.querySelector(':scope > div').textContent.trim();
if (audience === 'mobile') {
block.closest('.section')?.remove();
}

const parentSection = block.closest('.section');
const data = collectFloatingButtonData(block);

const blockWrapper = createFloatingButton(
block,
parentSection ? audience : null,
data,
);

const blockLinks = blockWrapper.querySelectorAll('a');
if (blockLinks && blockLinks.length > 0) {
formatDynamicCartLink(blockLinks[0]);
const linksPopulated = new CustomEvent('linkspopulated', { detail: blockLinks });
document.dispatchEvent(linksPopulated);
}
}
43 changes: 43 additions & 0 deletions express/blocks/floating-buttons/floating-buttons.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
div[class='section section-wrapper floating-buttons-container'] {
padding: 0;
}

.floating-buttons {
position: fixed;
bottom: 0;
background: linear-gradient(180deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.1) 20%, rgba(255,255,255,0.95) 70%, rgba(255,255,255,1) 78%);
width: 100%;
left: 0;
padding-bottom: 24px;
transition: bottom 0.4s;
z-index: 99;
max-width: none;
}

.floating-buttons > div > div {
max-height: 150px;
display: flex;
align-items: stretch;
justify-content: center;
flex-wrap: wrap;
}

.floating-buttons.hidden {
bottom: -200px;
}

.floating-buttons > div > div > a.button:any-link {
flex: 1 0 auto;
border-radius: 100px;
display: flex;
align-items: center;
justify-content: center;
margin: 4px 8px;
}

@media screen and (min-width: 900px) {
.floating-buttons > div > div > a.button:any-link {
flex: initial;
display: inline-block;
}
}
66 changes: 66 additions & 0 deletions express/blocks/floating-buttons/floating-buttons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import BlockMediator from '../../scripts/block-mediator.min.js';
import { formatDynamicCartLink } from '../../scripts/utils/pricing.js';

function initScrollWatcher(block) {
const hideOnIntersect = new IntersectionObserver((entries) => {
const notIntersecting = entries.every((entry) => !entry.isIntersecting);

if (notIntersecting) {
block.classList.remove('hidden');
} else {
block.classList.add('hidden');
}
}, {
root: null,
rootMargin: '32px',
threshold: 0,
});

const footer = document.querySelector('footer');
if (footer) hideOnIntersect.observe(footer);

const primaryCta = BlockMediator.get('primaryCtaUrl');
if (!primaryCta) return;

const primaryUrl = new URL(primaryCta);

const pageCta = Array.from(
document.querySelectorAll('.section:first-of-type a.primaryCTA, .section:first-of-type a.cta, .section:first-of-type a.con-button, .section:first-of-type a.button'),
).find((a) => a.href === primaryUrl.href);

if (pageCta) hideOnIntersect.observe(pageCta);
}

export default async function decorate(block) {
const buttons = block.querySelectorAll('a');
block.classList.add('hidden');

buttons.forEach((btn) => {
const parentEl = btn.parentElement;
formatDynamicCartLink(btn);
if (['EM', 'STRONG'].includes(parentEl.tagName)) {
if (parentEl.tagName === 'EM') {
btn.classList.add('primary', 'reverse');
btn.classList.remove('accent');
}

if (parentEl.tagName === 'STRONG') {
btn.classList.add('gradient');
}

parentEl.parentElement.replaceChild(btn, parentEl);
} else {
btn.classList.add('accent', 'cta');
}

if (btn.parentElement.classList.contains('button-container') || btn.parentElement.tagName === 'P') {
btn.parentElement.parentElement.replaceChild(btn, btn.parentElement);
}

btn.classList.add('button', 'xlarge');
});

initScrollWatcher(block);

return block;
}
2 changes: 1 addition & 1 deletion express/blocks/fullscreen-marquee/fullscreen-marquee.css
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@
transition: .5s opacity ease-in;
}

.fullscreen-marquee .button-container.free-plan-container {
.fullscreen-marquee p.button-container {
vhargrave marked this conversation as resolved.
Show resolved Hide resolved
margin-left: auto;
margin-right: auto;
}
Expand Down
189 changes: 189 additions & 0 deletions express/blocks/multifunction-button/multifunction-button.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
.floating-button-wrapper.multifunction {
flex-direction: column-reverse;
align-items: center;
transform: translateX(-50%);
left: 50%;
width: max-content;
height: auto;
background: unset
}

.floating-button-wrapper.multifunction.clamped {
width: auto;
}

.floating-button-wrapper.multifunction::before {
content: '';
position: fixed;
bottom: 0;
height: 150px;
width: 100vw;
background: linear-gradient(180deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.1) 20%, rgba(255,255,255,0.95) 70%, rgba(255,255,255,1) 78%);;
}

.floating-button-wrapper.multifunction .toolbox {
display: flex;
pointer-events: auto;
background-color: var(--color-white);
box-sizing: border-box;
padding: 24px 0;
transform: translateY(72px);
width: 100%;
max-height: 0;
border-radius: 32px;
overflow: hidden;
flex-direction: column;
text-align: left;
bottom: 0;
z-index: 1;

}

.floating-button-wrapper.multifunction .toolbox:after {
content: '';
position: absolute;
border-radius: 32px;
left: 0;
bottom: 0;
height: 64px;
width: 100%;
background-color: white;

}

.floating-button-wrapper.multifunction.with-transition .toolbox,
.floating-button-wrapper.multifunction.with-transition .toolbox:after {
transition: 0.5s;
}

.floating-button-wrapper.multifunction .toolbox.hidden {
display: none;
}

.floating-button-wrapper.multifunction .floating-button .toggle-button {
position: absolute;
left: 29px;
height: 18px;
padding: 4px;
width: 18px;
bottom: 50%;
transform: translateY(50%);
transition: transform 0.2s;
z-index: 2;
}

.floating-button-wrapper.multifunction .floating-button .toggle-button .lottie-plus-animation {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 80px;
width: 120px;
pointer-events: none;
transition: opacity 0.2s;
}

.floating-button-wrapper.multifunction.toolbox-opened .floating-button .toggle-button {
transform: translateY(50%) rotate(45deg);
}

.floating-button-wrapper.multifunction.toolbox-opened .floating-button .toggle-button .lottie-plus-animation {
opacity: 0;
}

.floating-button-wrapper.multifunction.toolbox-opened .toolbox {
max-height: 500px;
padding-bottom: 64px;
transform: translateY(64px);
z-index: 1;
}

.floating-button-wrapper.multifunction.with-transition .floating-button {
transition: all .2s;
}

.floating-button-wrapper.multifunction .floating-button.toolbox-opened {
background-color: var(--color-white);
}

.floating-button-wrapper.multifunction .toolbox .notch {
position: absolute;
padding: 6px;
top: 4px;
left: 50%;
transform: translateX(-50%);
}

.floating-button-wrapper.multifunction .toolbox .notch-pill {
border-radius: 20px;
height: 4px;
width: 36px;
background: var(--color-gray-300);
}

.floating-button-wrapper.multifunction .toolbox .badge {
position: absolute;
max-width: 120px;
top: -8px;
right: 32px;
transition: all 0.5s;
}

.floating-button-wrapper.multifunction .toolbox .tool {
display: flex;
align-items: center;
margin-bottom: 12px;
}

.floating-button-wrapper.multifunction .toolbox .tool:first-of-type {
padding-right: 120px;
}

.floating-button-wrapper.multifunction .toolbox .toolbox-top {
margin: 0 32px 12px 32px;
border-bottom: 1px solid var(--color-gray-300);
}

.floating-button-wrapper.multifunction .toolbox .toolbox-bottom {
margin: 0 32px;
}

.floating-button-wrapper.multifunction .toolbox .tool img,
.floating-button-wrapper.multifunction .toolbox .tool svg {
color: var(--color-black);
fill: var(--color-black);
height: 22px;
width: 22px;
margin-right: 12px;
object-fit: contain;
}

.floating-button-wrapper.multifunction .toolbox .tool a {
font-size: 16px;
line-height: 21px;
color: var(--color-black);
}

.floating-button-wrapper.multifunction .toolbox-background {
position: fixed;
pointer-events: none;
bottom: -50vh;
left: unset;
transform: unset;
height: 200vh;
width: 100vw;
z-index: 0;
opacity: 0;
transition: opacity 0.5s;
}

.floating-button-wrapper.multifunction.toolbox-opened .toolbox-background {
pointer-events: auto;
background-color: var(--color-black);
opacity: 0.75;
}

.floating-button-wrapper.multifunction.floating-button--hidden .toolbox,
.floating-button-wrapper.multifunction.floating-button--hidden .toolbox-background {
opacity: 0;
}
Loading
Loading