Skip to content

Commit 8495c0e

Browse files
committed
refactor(footer): improve code quality and accessibility
- Extract inline JavaScript to external file (newsletter.js) - Replace inline styles with CSS classes for better maintainability - Add proper ARIA labels and semantic HTML for accessibility - Add JSDoc comments for better code documentation - Add visually-hidden class for accessible form labels - Use Hugo asset pipeline for JavaScript loading with defer attribute
1 parent 8003d2a commit 8495c0e

File tree

3 files changed

+114
-49
lines changed

3 files changed

+114
-49
lines changed

assets/js/newsletter.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Newsletter subscription form handler
2+
document.addEventListener('DOMContentLoaded', function() {
3+
const form = document.getElementById('newsletter-form');
4+
const emailInput = document.getElementById('newsletter-email');
5+
const messageDiv = document.getElementById('newsletter-message');
6+
7+
if (!form || !emailInput || !messageDiv) return;
8+
9+
/**
10+
* Display a message to the user
11+
* @param {string} text - Message text to display
12+
* @param {boolean} isError - Whether this is an error message
13+
*/
14+
function showMessage(text, isError) {
15+
messageDiv.textContent = text;
16+
messageDiv.style.color = isError ? '#ff6b6b' : '#00d3a9';
17+
messageDiv.setAttribute('role', isError ? 'alert' : 'status');
18+
messageDiv.setAttribute('aria-live', 'polite');
19+
}
20+
21+
/**
22+
* Clear the message display
23+
*/
24+
function clearMessage() {
25+
messageDiv.textContent = '';
26+
messageDiv.removeAttribute('role');
27+
messageDiv.removeAttribute('aria-live');
28+
}
29+
30+
/**
31+
* Validate email format
32+
* @param {string} email - Email address to validate
33+
* @returns {boolean} Whether the email is valid
34+
*/
35+
function isValidEmail(email) {
36+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
37+
return emailRegex.test(email);
38+
}
39+
40+
// Clear message when user starts typing
41+
emailInput.addEventListener('input', clearMessage);
42+
43+
// Handle form submission
44+
form.addEventListener('submit', function(e) {
45+
e.preventDefault();
46+
47+
const email = emailInput.value.trim();
48+
49+
// Check if email is empty
50+
if (!email) {
51+
showMessage('Please enter your email address', true);
52+
emailInput.focus();
53+
return false;
54+
}
55+
56+
// Validate email format
57+
if (!isValidEmail(email)) {
58+
showMessage('Please enter a valid email address', true);
59+
emailInput.focus();
60+
return false;
61+
}
62+
63+
// Success message
64+
showMessage('Thank you for subscribing!', false);
65+
emailInput.value = '';
66+
67+
return false;
68+
});
69+
});

assets/scss/_footer_project.scss

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,35 @@
280280
border: none;
281281
}
282282

283+
.newsletter-container {
284+
display: flex;
285+
align-items: flex-start;
286+
flex-direction: column;
287+
}
288+
289+
.newsletter-input-row {
290+
display: flex;
291+
align-items: center;
292+
}
293+
294+
.newsletter-message {
295+
margin-top: 0.5rem;
296+
font-size: 0.9rem;
297+
min-height: 1.5rem;
298+
}
299+
300+
.visually-hidden {
301+
position: absolute;
302+
width: 1px;
303+
height: 1px;
304+
margin: -1px;
305+
padding: 0;
306+
overflow: hidden;
307+
clip: rect(0, 0, 0, 0);
308+
white-space: nowrap;
309+
border: 0;
310+
}
311+
283312
.footer-hr {
284313
width: 100%;
285314
color: $white;

layouts/partials/footer.html

Lines changed: 16 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -62,66 +62,33 @@ <h5 class="footer-h5"><a href="{{ .url }}">{{ .name }}</a></h5>
6262
</div>
6363
<div class="row footer-info2 subscribe">
6464
<div class="footer-end">
65-
<form name="contactform" id="newsletter-form">
65+
<form name="contactform" id="newsletter-form" aria-label="Newsletter subscription form">
6666
<div>
6767
<p>
6868
Subscribe to our Newsletter
6969
</p>
70-
<div style="display: flex; align-items: flex-start; flex-direction: column;">
71-
<div style="display: flex; align-items: center;">
72-
<input class="footer-input" id="newsletter-email" type="email" placeholder="Email Address" required />
70+
<div class="newsletter-container">
71+
<div class="newsletter-input-row">
72+
<label for="newsletter-email" class="visually-hidden">Email Address</label>
73+
<input
74+
class="footer-input"
75+
id="newsletter-email"
76+
type="email"
77+
placeholder="Email Address"
78+
aria-required="true"
79+
aria-describedby="newsletter-message"
80+
required
81+
/>
7382
<button class="footer-button" title="Subscribe" type="submit">Subscribe</button>
7483
</div>
75-
<div id="newsletter-message" style="margin-top: 0.5rem; font-size: 0.9rem; min-height: 1.5rem;"></div>
84+
<div id="newsletter-message" class="newsletter-message" aria-live="polite"></div>
7685
</div>
7786
</div>
7887
</form>
7988
</div>
8089
</div>
81-
<script>
82-
document.addEventListener('DOMContentLoaded', function() {
83-
const form = document.getElementById('newsletter-form');
84-
const emailInput = document.getElementById('newsletter-email');
85-
const messageDiv = document.getElementById('newsletter-message');
86-
87-
function showMessage(text, isError) {
88-
messageDiv.textContent = text;
89-
messageDiv.style.color = isError ? '#ff6b6b' : '#00d3a9';
90-
}
91-
92-
function clearMessage() {
93-
messageDiv.textContent = '';
94-
}
95-
96-
if (form) {
97-
emailInput.addEventListener('input', clearMessage);
98-
99-
form.addEventListener('submit', function(e) {
100-
e.preventDefault();
101-
102-
const email = emailInput.value.trim();
103-
104-
if (!email) {
105-
showMessage('Please enter your email address', true);
106-
emailInput.focus();
107-
return false;
108-
}
109-
110-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
111-
if (!emailRegex.test(email)) {
112-
showMessage('Please enter a valid email address', true);
113-
emailInput.focus();
114-
return false;
115-
}
116-
117-
showMessage('Thank you for subscribing!', false);
118-
emailInput.value = '';
119-
120-
return false;
121-
});
122-
}
123-
});
124-
</script>
90+
{{ $newsletter := resources.Get "js/newsletter.js" }}
91+
<script src="{{ $newsletter.Permalink }}" defer></script>
12592
</div>
12693
</div>
12794
<hr class="footer-hr" />

0 commit comments

Comments
 (0)