pages/_includes/scripts/newsletter.liquid
Andrew Boyer 0ac9e447ca
Added support for a newsletter (#2517)
In reference to idea:
https://github.com/alshedivat/al-folio/discussions/2097
In reference to request:
https://github.com/alshedivat/al-folio/issues/923#issuecomment-2171924663

Added support to integrate a [loops.so](https://loops.so/) mailing list
into the site.

To use, you need to enable `newsletter` in `_config.yml`. You also must
specify a loops endpoint (although I think any mailing list endpoint can
work), which you can get when you set up a mailing list on loops. More
documentation on loops: [here](https://loops.so/docs/forms/custom-form).

Once that is enabled, the behavior is different depending on how you
specified your footer to behave in `_config.yml`. If `footer_fixed:
true`, then the sign up will appear at the bottom of the about page, as
well as at the bottom of blog posts, if you enable `related_posts`.

If `footer_fixed: false`, then the newsletter signup will be in the
footer (on every page), like it is in on [my
website](https://asboyer.com).

I'm not attached to the placement of the signup, and you can choose to
include it wherever you want with `{% include scripts/newsletter.liquid
%}`. Also if you include positional variables into that, you can choose
how you center the signup. So `{% include scripts/newsletter.liquid
left=true %}` positions the signup bar to the left.

Here are some screenshots below:
## Dark version

![image](https://github.com/alshedivat/al-folio/assets/52665298/af7fdb81-6e5f-47a9-958b-4cb93bba9e8f)

## Light version

![image](https://github.com/alshedivat/al-folio/assets/52665298/927f8bc5-b481-448b-ae5e-6f5b1c613243)
I think the input field color should probably change to maybe be light
for both themes? What do you think? I think the dark background looks
cool, but I don't usually see that done like that on other sites.

## Footer fixed

![image](https://github.com/alshedivat/al-folio/assets/52665298/c52f3dc1-0e45-400e-8b71-eeb00d00cb01)


![image](https://github.com/alshedivat/al-folio/assets/52665298/678a2d45-88ab-4d9a-b8cc-9fc6db26d744)

## Footer not fixed

![image](https://github.com/alshedivat/al-folio/assets/52665298/fd2c0228-2bce-4335-ac3c-5cb20a3307e2)


![image](https://github.com/alshedivat/al-folio/assets/52665298/f594b4f2-67e0-4f2b-a3e8-febd579aaf19)
To clarify, if footer isn't fixed, the email signup will appear on every
page.

---------

Co-authored-by: George <31376482+george-gca@users.noreply.github.com>
2024-06-19 14:49:19 -03:00

177 lines
6.0 KiB
Plaintext

<div
class="newsletter-form-container"
{% if include.center %}
style="margin: 20px"
{% endif %}
>
<form
class="newsletter-form"
action="https://app.loops.so/api/newsletter-form/{{ site.newsletter.endpoint }}"
method="POST"
style="justify-content: {% if include.left %}flex-start{% elsif include.right %}flex-end{% else %}center{% endif %}"
>
<input
class="newsletter-form-input"
name="newsletter-form-input"
type="email"
placeholder="user@example.com"
required=""
>
<button
type="submit"
class="newsletter-form-button"
style="justify-content: {% if include.left %}flex-start{% elsif include.right %}flex-end{% else %}center{% endif %}"
>
subscribe
</button>
<button
type="button"
class="newsletter-loading-button"
style="justify-content: {% if include.left %}flex-start{% elsif include.right %}flex-end{% else %}center{% endif %}"
>
Please wait...
</button>
</form>
<div
class="newsletter-success"
style="justify-content: {% if include.left %}flex-start{% elsif include.right %}flex-end{% else %}center{% endif %}"
>
<p class="newsletter-success-message">You're subscribed!</p>
</div>
<div
class="newsletter-error"
style="justify-content: {% if include.left %}flex-start{% elsif include.right %}flex-end{% else %}center{% endif %}"
>
<p class="newsletter-error-message">Oops! Something went wrong, please try again</p>
</div>
<button
class="newsletter-back-button"
type="button"
onmouseout='this.style.textDecoration="none"'
onmouseover='this.style.textDecoration="underline"'
>
&larr; Back
</button>
</div>
<script>
function submitHandler(event) {
event.preventDefault();
var container = event.target.parentNode;
var form = container.querySelector('.newsletter-form');
var formInput = container.querySelector('.newsletter-form-input');
var success = container.querySelector('.newsletter-success');
var errorContainer = container.querySelector('.newsletter-error');
var errorMessage = container.querySelector('.newsletter-error-message');
var backButton = container.querySelector('.newsletter-back-button');
var submitButton = container.querySelector('.newsletter-form-button');
var loadingButton = container.querySelector('.newsletter-loading-button');
const rateLimit = () => {
errorContainer.style.display = 'flex';
errorMessage.innerText = 'Too many signups, please try again in a little while';
submitButton.style.display = 'none';
formInput.style.display = 'none';
backButton.style.display = 'block';
};
// Compare current time with time of previous sign up
var time = new Date();
var timestamp = time.valueOf();
var previousTimestamp = localStorage.getItem('loops-form-timestamp');
// If last sign up was less than a minute ago
// display error
if (previousTimestamp && Number(previousTimestamp) + 60000 > timestamp) {
rateLimit();
return;
}
localStorage.setItem('loops-form-timestamp', timestamp);
submitButton.style.display = 'none';
loadingButton.style.display = 'flex';
var formBody = 'userGroup=&email=' + encodeURIComponent(formInput.value);
fetch(event.target.action, {
method: 'POST',
body: formBody,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
})
.then((res) => [res.ok, res.json(), res])
.then(([ok, dataPromise, res]) => {
if (ok) {
// If response successful
// display success
success.style.display = 'flex';
form.reset();
} else {
// If response unsuccessful
// display error message or response status
dataPromise.then((data) => {
errorContainer.style.display = 'flex';
errorMessage.innerText = data.message ? data.message : res.statusText;
});
}
})
.catch((error) => {
// check for cloudflare error
if (error.message === 'Failed to fetch') {
rateLimit();
return;
}
// If error caught
// display error message if available
errorContainer.style.display = 'flex';
if (error.message) errorMessage.innerText = error.message;
localStorage.setItem('loops-form-timestamp', '');
})
.finally(() => {
formInput.style.display = 'none';
loadingButton.style.display = 'none';
backButton.style.display = 'block';
});
}
function resetFormHandler(event) {
var container = event.target.parentNode;
var formInput = container.querySelector('.newsletter-form-input');
var success = container.querySelector('.newsletter-success');
var errorContainer = container.querySelector('.newsletter-error');
var errorMessage = container.querySelector('.newsletter-error-message');
var backButton = container.querySelector('.newsletter-back-button');
var submitButton = container.querySelector('.newsletter-form-button');
success.style.display = 'none';
errorContainer.style.display = 'none';
errorMessage.innerText = 'Oops! Something went wrong, please try again';
backButton.style.display = 'none';
formInput.style.display = 'flex';
submitButton.style.display = 'flex';
}
var formContainers = document.getElementsByClassName('newsletter-form-container');
for (var i = 0; i < formContainers.length; i++) {
var formContainer = formContainers[i];
var handlersAdded = formContainer.classList.contains('newsletter-handlers-added');
if (handlersAdded) continue;
formContainer.querySelector('.newsletter-form').addEventListener('submit', submitHandler);
formContainer.querySelector('.newsletter-back-button').addEventListener('click', resetFormHandler);
formContainer.classList.add('newsletter-handlers-added');
}
</script>
<noscript>
<style>
.newsletter-form-container {
display: none;
}
</style>
</noscript>