jscom_ice 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +66 -4
- data/_includes/footer.html +1 -0
- data/_includes/newsletter-signup-footer.html +78 -0
- data/_includes/newsletter-status-check.html +133 -0
- data/_includes/newsletter-subscribe-form.html +90 -0
- data/_includes/newsletter-unsubscribe-form.html +79 -0
- data/_sass/component/_all-components.scss +1 -0
- data/_sass/component/_newsletter.scss +272 -0
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5757d0be4848c97f09910726431394c801472f925e16836152e2d1e12e3ce5ae
|
|
4
|
+
data.tar.gz: a4583d6a5656492ed1f628ad50537f9e6ae04126d5308df120f19e206272b417
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 679e6d2c448bf013cdb31eb37912be8feadf02d43f435786031392de4f9a6366775ec53a9216b0923b9c40cf075bb7c0540c64072a0a899ced0be0c4bd38749a
|
|
7
|
+
data.tar.gz: 4e86fcc53e0c1638dd54c4a918fb0bcc123207eb2fa3ad7f56955a0200215113d3b2fb041ad0d6302f10bd51a387c8e4f1a53af9fbca68fb7e4dcedf874274d8
|
data/README.md
CHANGED
|
@@ -2,23 +2,85 @@
|
|
|
2
2
|
|
|
3
3
|
A Jekyll theme for (johnsosoka.com)[https://johnsosoka.com]
|
|
4
4
|
|
|
5
|
-
**NOTE:** This repository and theme are open source, but not really meant for public consumption. If you would like to use this
|
|
5
|
+
**NOTE:** This repository and theme are open source, but not really meant for public consumption. If you would like to use this
|
|
6
6
|
theme, please fork the repository and make any changes you would like.
|
|
7
7
|
|
|
8
8
|
## Usage
|
|
9
9
|
|
|
10
|
-
1. Add to gemfile:
|
|
10
|
+
1. Add to gemfile:
|
|
11
11
|
```
|
|
12
12
|
group :jekyll_plugins do
|
|
13
13
|
# jscom theme
|
|
14
|
-
gem "jscom_ice", '~>
|
|
15
|
-
|
|
14
|
+
gem "jscom_ice", '~> 1.0.1'
|
|
15
|
+
|
|
16
16
|
end
|
|
17
17
|
```
|
|
18
18
|
2. Add to _config.yml:
|
|
19
19
|
```
|
|
20
20
|
theme: jscom_ice
|
|
21
21
|
```
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
### Newsletter Signup
|
|
26
|
+
|
|
27
|
+
The theme includes newsletter signup functionality that integrates with an API endpoint.
|
|
28
|
+
|
|
29
|
+
#### Footer Newsletter Signup
|
|
30
|
+
|
|
31
|
+
Add newsletter signup to your site footer with a compact, horizontal form. Configure in `_config.yml`:
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
# Newsletter Settings
|
|
35
|
+
newsletter:
|
|
36
|
+
api:
|
|
37
|
+
url: https://api.johnsosoka.com/v1/newsletter
|
|
38
|
+
footer:
|
|
39
|
+
enabled: true
|
|
40
|
+
title: "Newsletter Signup"
|
|
41
|
+
description: "Get random updates"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Configuration Options:**
|
|
45
|
+
- `newsletter.api.url` - Base URL for the newsletter API (required)
|
|
46
|
+
- `newsletter.footer.enabled` - Toggle footer signup form (default: false)
|
|
47
|
+
- `newsletter.footer.title` - Heading text for the footer signup
|
|
48
|
+
- `newsletter.footer.description` - Descriptive text below the heading
|
|
49
|
+
|
|
50
|
+
The footer signup form will appear between footer links and copyright text when enabled.
|
|
51
|
+
|
|
52
|
+
#### Dedicated Newsletter Page
|
|
53
|
+
|
|
54
|
+
Create a full-featured newsletter management page with subscribe, unsubscribe, and status check forms:
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
---
|
|
58
|
+
layout: page
|
|
59
|
+
title: Newsletter
|
|
60
|
+
permalink: /newsletter/
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
<div class="newsletter-page-container">
|
|
64
|
+
{% include newsletter-subscribe-form.html %}
|
|
65
|
+
{% include newsletter-unsubscribe-form.html %}
|
|
66
|
+
{% include newsletter-status-check.html %}
|
|
67
|
+
</div>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Available Includes:**
|
|
71
|
+
- `newsletter-subscribe-form.html` - Full subscription form with email and optional name fields
|
|
72
|
+
- `newsletter-unsubscribe-form.html` - Unsubscribe by email
|
|
73
|
+
- `newsletter-status-check.html` - Check subscription status with formatted results
|
|
74
|
+
|
|
75
|
+
#### API Integration
|
|
76
|
+
|
|
77
|
+
The newsletter components expect the following API endpoints:
|
|
78
|
+
|
|
79
|
+
- `POST /v1/newsletter` - Subscribe (body: `{"email": "user@example.com", "name": "Optional Name"}`)
|
|
80
|
+
- `DELETE /v1/newsletter` - Unsubscribe (body: `{"email": "user@example.com"}`)
|
|
81
|
+
- `GET /v1/newsletter/status?email=user@example.com` - Check status
|
|
82
|
+
|
|
83
|
+
Responses are displayed with Bootstrap-styled alerts for success/error messaging.
|
|
22
84
|
|
|
23
85
|
## Release
|
|
24
86
|
|
data/_includes/footer.html
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{% if site.newsletter.footer.enabled %}
|
|
2
|
+
<div class="newsletter-footer-signup">
|
|
3
|
+
<div class="newsletter-container">
|
|
4
|
+
<div class="newsletter-content">
|
|
5
|
+
<div class="newsletter-text">
|
|
6
|
+
<h5 class="newsletter-title">{{ site.newsletter.footer.title | default: "Stay Updated" }}</h5>
|
|
7
|
+
<p class="newsletter-description">{{ site.newsletter.footer.description | default: "Get notified about new blog posts and updates" }}</p>
|
|
8
|
+
</div>
|
|
9
|
+
<form id="newsletterFooterForm" class="newsletter-form">
|
|
10
|
+
<div id="newsletter-notification" class="alert mt-2" role="alert" style="display: none;"></div>
|
|
11
|
+
<div class="newsletter-input-group">
|
|
12
|
+
<input type="email"
|
|
13
|
+
class="form-control newsletter-email-input"
|
|
14
|
+
id="newsletter-email"
|
|
15
|
+
name="newsletter_email"
|
|
16
|
+
placeholder="Enter your email"
|
|
17
|
+
required>
|
|
18
|
+
<button type="submit" class="btn btn-primary newsletter-submit-btn" id="newsletter-submit">
|
|
19
|
+
Subscribe
|
|
20
|
+
</button>
|
|
21
|
+
</div>
|
|
22
|
+
</form>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<script src="/assets/js/jquery-3.7.0.min.js"></script>
|
|
28
|
+
<script>
|
|
29
|
+
function submitNewsletterFooter(email) {
|
|
30
|
+
$.ajax({
|
|
31
|
+
url: "{{ site.newsletter.api.url }}",
|
|
32
|
+
type: "POST",
|
|
33
|
+
contentType: "application/json",
|
|
34
|
+
data: JSON.stringify({
|
|
35
|
+
email: email,
|
|
36
|
+
name: "Newsletter Subscriber" // Default name for footer signups
|
|
37
|
+
}),
|
|
38
|
+
success: function(data) {
|
|
39
|
+
console.log(data);
|
|
40
|
+
$('#newsletter-notification')
|
|
41
|
+
.removeClass('alert-danger')
|
|
42
|
+
.addClass('alert-success')
|
|
43
|
+
.text('Successfully subscribed! Check your email.')
|
|
44
|
+
.show();
|
|
45
|
+
$('#newsletter-email').val('');
|
|
46
|
+
},
|
|
47
|
+
error: function(xhr) {
|
|
48
|
+
console.log("Error in the request:", xhr);
|
|
49
|
+
var errorMsg = 'Something went wrong. Please try again.';
|
|
50
|
+
if (xhr.responseJSON && xhr.responseJSON.error) {
|
|
51
|
+
errorMsg = xhr.responseJSON.error;
|
|
52
|
+
}
|
|
53
|
+
$('#newsletter-notification')
|
|
54
|
+
.removeClass('alert-success')
|
|
55
|
+
.addClass('alert-danger')
|
|
56
|
+
.text(errorMsg)
|
|
57
|
+
.show();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
$('#newsletterFooterForm').on('submit', function(e) {
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
var email = $('#newsletter-email').val().trim();
|
|
65
|
+
|
|
66
|
+
if (!email) {
|
|
67
|
+
$('#newsletter-notification')
|
|
68
|
+
.removeClass('alert-success')
|
|
69
|
+
.addClass('alert-danger')
|
|
70
|
+
.text('Please enter a valid email address.')
|
|
71
|
+
.show();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
submitNewsletterFooter(email);
|
|
76
|
+
});
|
|
77
|
+
</script>
|
|
78
|
+
{% endif %}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<div class="newsletter-section">
|
|
2
|
+
<h2 class="newsletter-section-title">Check Subscription Status</h2>
|
|
3
|
+
<p class="newsletter-section-description">
|
|
4
|
+
Enter your email address to check your current newsletter subscription status.
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<form id="newsletterStatusForm">
|
|
8
|
+
<div id="status-notification" class="alert mt-3" role="alert" style="display: none;"></div>
|
|
9
|
+
|
|
10
|
+
<div class="form-group">
|
|
11
|
+
<input type="email"
|
|
12
|
+
class="form-control"
|
|
13
|
+
id="status-email"
|
|
14
|
+
name="status_email"
|
|
15
|
+
placeholder="Email Address"
|
|
16
|
+
required>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="form-buttons">
|
|
20
|
+
<button type="submit" class="btn btn-primary" id="status-submit">Check Status</button>
|
|
21
|
+
</div>
|
|
22
|
+
</form>
|
|
23
|
+
|
|
24
|
+
<div id="status-result" class="newsletter-status-result" style="display: none;">
|
|
25
|
+
<div class="status-row">
|
|
26
|
+
<span class="status-label">Email:</span>
|
|
27
|
+
<span class="status-value" id="result-email"></span>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="status-row">
|
|
30
|
+
<span class="status-label">Status:</span>
|
|
31
|
+
<span class="status-value" id="result-status"></span>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="status-row" id="subscribed-at-row" style="display: none;">
|
|
34
|
+
<span class="status-label">Subscribed On:</span>
|
|
35
|
+
<span class="status-value" id="result-subscribed-at"></span>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="status-row" id="updated-at-row" style="display: none;">
|
|
38
|
+
<span class="status-label">Last Updated:</span>
|
|
39
|
+
<span class="status-value" id="result-updated-at"></span>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<script src="/assets/js/jquery-3.7.0.min.js"></script>
|
|
45
|
+
<script>
|
|
46
|
+
function checkNewsletterStatus(email) {
|
|
47
|
+
$.ajax({
|
|
48
|
+
url: "{{ site.newsletter.api.url }}/status?email=" + encodeURIComponent(email),
|
|
49
|
+
type: "GET",
|
|
50
|
+
success: function(data) {
|
|
51
|
+
console.log(data);
|
|
52
|
+
displayStatusResult(data);
|
|
53
|
+
$('#status-notification').hide();
|
|
54
|
+
},
|
|
55
|
+
error: function(xhr) {
|
|
56
|
+
console.log("Error in the request:", xhr);
|
|
57
|
+
var errorMsg = 'Something went wrong. Please try again.';
|
|
58
|
+
if (xhr.responseJSON && xhr.responseJSON.error) {
|
|
59
|
+
errorMsg = xhr.responseJSON.error;
|
|
60
|
+
}
|
|
61
|
+
$('#status-notification')
|
|
62
|
+
.removeClass('alert-success')
|
|
63
|
+
.addClass('alert-danger')
|
|
64
|
+
.text(errorMsg)
|
|
65
|
+
.show();
|
|
66
|
+
$('#status-result').hide();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function displayStatusResult(data) {
|
|
72
|
+
// Set email
|
|
73
|
+
$('#result-email').text(data.email);
|
|
74
|
+
|
|
75
|
+
// Set status with appropriate styling
|
|
76
|
+
var statusText = data.status.toUpperCase();
|
|
77
|
+
var statusElement = $('#result-status');
|
|
78
|
+
statusElement.removeClass('status-active status-inactive status-not-found');
|
|
79
|
+
|
|
80
|
+
if (data.status === 'active') {
|
|
81
|
+
statusElement.addClass('status-active').text(statusText);
|
|
82
|
+
} else if (data.status === 'inactive') {
|
|
83
|
+
statusElement.addClass('status-inactive').text(statusText);
|
|
84
|
+
} else {
|
|
85
|
+
statusElement.addClass('status-not-found').text(statusText);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Show/hide timestamp rows based on data availability
|
|
89
|
+
if (data.subscribed_at) {
|
|
90
|
+
var subscribedDate = new Date(data.subscribed_at * 1000).toLocaleDateString('en-US', {
|
|
91
|
+
year: 'numeric',
|
|
92
|
+
month: 'long',
|
|
93
|
+
day: 'numeric'
|
|
94
|
+
});
|
|
95
|
+
$('#result-subscribed-at').text(subscribedDate);
|
|
96
|
+
$('#subscribed-at-row').show();
|
|
97
|
+
} else {
|
|
98
|
+
$('#subscribed-at-row').hide();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (data.updated_at) {
|
|
102
|
+
var updatedDate = new Date(data.updated_at * 1000).toLocaleDateString('en-US', {
|
|
103
|
+
year: 'numeric',
|
|
104
|
+
month: 'long',
|
|
105
|
+
day: 'numeric'
|
|
106
|
+
});
|
|
107
|
+
$('#result-updated-at').text(updatedDate);
|
|
108
|
+
$('#updated-at-row').show();
|
|
109
|
+
} else {
|
|
110
|
+
$('#updated-at-row').hide();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Show the result container
|
|
114
|
+
$('#status-result').show();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
$('#newsletterStatusForm').on('submit', function(e) {
|
|
118
|
+
e.preventDefault();
|
|
119
|
+
var email = $('#status-email').val().trim();
|
|
120
|
+
|
|
121
|
+
if (!email) {
|
|
122
|
+
$('#status-notification')
|
|
123
|
+
.removeClass('alert-success')
|
|
124
|
+
.addClass('alert-danger')
|
|
125
|
+
.text('Please enter a valid email address.')
|
|
126
|
+
.show();
|
|
127
|
+
$('#status-result').hide();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
checkNewsletterStatus(email);
|
|
132
|
+
});
|
|
133
|
+
</script>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<div class="newsletter-section">
|
|
2
|
+
<h2 class="newsletter-section-title">Subscribe to Newsletter</h2>
|
|
3
|
+
<p class="newsletter-section-description">
|
|
4
|
+
Enter your email address to receive updates about new blog posts, projects, and announcements.
|
|
5
|
+
We respect your privacy and will never share your email address.
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<form id="newsletterSubscribeForm">
|
|
9
|
+
<div id="subscribe-notification" class="alert mt-3" role="alert" style="display: none;"></div>
|
|
10
|
+
|
|
11
|
+
<div class="form-group">
|
|
12
|
+
<input type="email"
|
|
13
|
+
class="form-control"
|
|
14
|
+
id="subscribe-email"
|
|
15
|
+
name="subscribe_email"
|
|
16
|
+
placeholder="Email Address"
|
|
17
|
+
required>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div class="form-group">
|
|
21
|
+
<input type="text"
|
|
22
|
+
class="form-control"
|
|
23
|
+
id="subscribe-name"
|
|
24
|
+
name="subscribe_name"
|
|
25
|
+
placeholder="Name (Optional)">
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div class="form-buttons">
|
|
29
|
+
<button type="submit" class="btn btn-primary" id="subscribe-submit">Subscribe to Newsletter</button>
|
|
30
|
+
</div>
|
|
31
|
+
</form>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<script src="/assets/js/jquery-3.7.0.min.js"></script>
|
|
35
|
+
<script>
|
|
36
|
+
function submitNewsletterSubscribe(email, name) {
|
|
37
|
+
$.ajax({
|
|
38
|
+
url: "{{ site.newsletter.api.url }}",
|
|
39
|
+
type: "POST",
|
|
40
|
+
contentType: "application/json",
|
|
41
|
+
data: JSON.stringify({
|
|
42
|
+
email: email,
|
|
43
|
+
name: name || "Newsletter Subscriber"
|
|
44
|
+
}),
|
|
45
|
+
success: function(data) {
|
|
46
|
+
console.log(data);
|
|
47
|
+
$('#subscribe-notification')
|
|
48
|
+
.removeClass('alert-danger')
|
|
49
|
+
.addClass('alert-success')
|
|
50
|
+
.text('Successfully subscribed! You will receive a confirmation shortly.')
|
|
51
|
+
.show();
|
|
52
|
+
clearSubscribeForm();
|
|
53
|
+
},
|
|
54
|
+
error: function(xhr) {
|
|
55
|
+
console.log("Error in the request:", xhr);
|
|
56
|
+
var errorMsg = 'Something went wrong. Please try again.';
|
|
57
|
+
if (xhr.responseJSON && xhr.responseJSON.error) {
|
|
58
|
+
errorMsg = xhr.responseJSON.error;
|
|
59
|
+
}
|
|
60
|
+
$('#subscribe-notification')
|
|
61
|
+
.removeClass('alert-success')
|
|
62
|
+
.addClass('alert-danger')
|
|
63
|
+
.text(errorMsg)
|
|
64
|
+
.show();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function clearSubscribeForm() {
|
|
70
|
+
$('#subscribe-email').val('');
|
|
71
|
+
$('#subscribe-name').val('');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
$('#newsletterSubscribeForm').on('submit', function(e) {
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
var email = $('#subscribe-email').val().trim();
|
|
77
|
+
var name = $('#subscribe-name').val().trim();
|
|
78
|
+
|
|
79
|
+
if (!email) {
|
|
80
|
+
$('#subscribe-notification')
|
|
81
|
+
.removeClass('alert-success')
|
|
82
|
+
.addClass('alert-danger')
|
|
83
|
+
.text('Please enter a valid email address.')
|
|
84
|
+
.show();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
submitNewsletterSubscribe(email, name);
|
|
89
|
+
});
|
|
90
|
+
</script>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<div class="newsletter-section">
|
|
2
|
+
<h2 class="newsletter-section-title">Unsubscribe from Newsletter</h2>
|
|
3
|
+
<p class="newsletter-section-description">
|
|
4
|
+
Sorry to see you go! Enter your email address below to unsubscribe from the newsletter.
|
|
5
|
+
You can always re-subscribe at any time.
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<form id="newsletterUnsubscribeForm">
|
|
9
|
+
<div id="unsubscribe-notification" class="alert mt-3" role="alert" style="display: none;"></div>
|
|
10
|
+
|
|
11
|
+
<div class="form-group">
|
|
12
|
+
<input type="email"
|
|
13
|
+
class="form-control"
|
|
14
|
+
id="unsubscribe-email"
|
|
15
|
+
name="unsubscribe_email"
|
|
16
|
+
placeholder="Email Address"
|
|
17
|
+
required>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div class="form-buttons">
|
|
21
|
+
<button type="submit" class="btn btn-secondary" id="unsubscribe-submit">Unsubscribe from Newsletter</button>
|
|
22
|
+
</div>
|
|
23
|
+
</form>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<script src="/assets/js/jquery-3.7.0.min.js"></script>
|
|
27
|
+
<script>
|
|
28
|
+
function submitNewsletterUnsubscribe(email) {
|
|
29
|
+
$.ajax({
|
|
30
|
+
url: "{{ site.newsletter.api.url }}",
|
|
31
|
+
type: "DELETE",
|
|
32
|
+
contentType: "application/json",
|
|
33
|
+
data: JSON.stringify({
|
|
34
|
+
email: email
|
|
35
|
+
}),
|
|
36
|
+
success: function(data) {
|
|
37
|
+
console.log(data);
|
|
38
|
+
$('#unsubscribe-notification')
|
|
39
|
+
.removeClass('alert-danger')
|
|
40
|
+
.addClass('alert-success')
|
|
41
|
+
.text('Successfully unsubscribed. You will no longer receive our newsletter.')
|
|
42
|
+
.show();
|
|
43
|
+
clearUnsubscribeForm();
|
|
44
|
+
},
|
|
45
|
+
error: function(xhr) {
|
|
46
|
+
console.log("Error in the request:", xhr);
|
|
47
|
+
var errorMsg = 'Something went wrong. Please try again.';
|
|
48
|
+
if (xhr.responseJSON && xhr.responseJSON.error) {
|
|
49
|
+
errorMsg = xhr.responseJSON.error;
|
|
50
|
+
}
|
|
51
|
+
$('#unsubscribe-notification')
|
|
52
|
+
.removeClass('alert-success')
|
|
53
|
+
.addClass('alert-danger')
|
|
54
|
+
.text(errorMsg)
|
|
55
|
+
.show();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function clearUnsubscribeForm() {
|
|
61
|
+
$('#unsubscribe-email').val('');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
$('#newsletterUnsubscribeForm').on('submit', function(e) {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
var email = $('#unsubscribe-email').val().trim();
|
|
67
|
+
|
|
68
|
+
if (!email) {
|
|
69
|
+
$('#unsubscribe-notification')
|
|
70
|
+
.removeClass('alert-success')
|
|
71
|
+
.addClass('alert-danger')
|
|
72
|
+
.text('Please enter a valid email address.')
|
|
73
|
+
.show();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
submitNewsletterUnsubscribe(email);
|
|
78
|
+
});
|
|
79
|
+
</script>
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
// Newsletter component styling
|
|
2
|
+
|
|
3
|
+
// ===========================
|
|
4
|
+
// Footer Newsletter Signup
|
|
5
|
+
// ===========================
|
|
6
|
+
.newsletter-footer-signup {
|
|
7
|
+
margin: $spacing-xxl 0 $spacing-xl 0;
|
|
8
|
+
padding: $spacing-xl 0;
|
|
9
|
+
border-top: 1px solid rgba(138, 168, 255, 0.15);
|
|
10
|
+
|
|
11
|
+
.newsletter-container {
|
|
12
|
+
max-width: 800px;
|
|
13
|
+
margin: 0 auto;
|
|
14
|
+
padding: 0 $spacing-lg;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.newsletter-content {
|
|
18
|
+
text-align: center;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.newsletter-text {
|
|
22
|
+
margin-bottom: $spacing-lg;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.newsletter-title {
|
|
26
|
+
font-size: $large-font-size;
|
|
27
|
+
font-weight: $semibold-weight;
|
|
28
|
+
color: $dark-white;
|
|
29
|
+
margin-bottom: $spacing-sm;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.newsletter-description {
|
|
33
|
+
font-size: $base-font-size;
|
|
34
|
+
color: $darker-white;
|
|
35
|
+
margin-bottom: 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.newsletter-form {
|
|
39
|
+
// Override default form styling for compact footer form
|
|
40
|
+
margin: 0;
|
|
41
|
+
padding: 0;
|
|
42
|
+
background: transparent;
|
|
43
|
+
border: none;
|
|
44
|
+
box-shadow: none;
|
|
45
|
+
backdrop-filter: none;
|
|
46
|
+
-webkit-backdrop-filter: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.newsletter-input-group {
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
gap: $spacing-md;
|
|
53
|
+
max-width: 500px;
|
|
54
|
+
margin: 0 auto;
|
|
55
|
+
|
|
56
|
+
@media (min-width: 576px) {
|
|
57
|
+
flex-direction: row;
|
|
58
|
+
align-items: stretch;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.newsletter-email-input {
|
|
63
|
+
flex: 1;
|
|
64
|
+
margin-bottom: 0;
|
|
65
|
+
color: $dark-white !important;
|
|
66
|
+
|
|
67
|
+
&::placeholder {
|
|
68
|
+
color: $darker-white !important;
|
|
69
|
+
opacity: 0.6 !important;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@media (min-width: 576px) {
|
|
73
|
+
min-width: 300px;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.newsletter-submit-btn {
|
|
78
|
+
white-space: nowrap;
|
|
79
|
+
padding: $spacing-md $spacing-xl;
|
|
80
|
+
|
|
81
|
+
@media (min-width: 576px) {
|
|
82
|
+
flex-shrink: 0;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Alert styling for footer
|
|
87
|
+
.alert {
|
|
88
|
+
margin-top: $spacing-md;
|
|
89
|
+
margin-bottom: 0;
|
|
90
|
+
padding: $spacing-md;
|
|
91
|
+
border-radius: 8px;
|
|
92
|
+
font-weight: $medium-weight;
|
|
93
|
+
text-align: center;
|
|
94
|
+
max-width: 500px;
|
|
95
|
+
margin-left: auto;
|
|
96
|
+
margin-right: auto;
|
|
97
|
+
|
|
98
|
+
&.alert-success {
|
|
99
|
+
background-color: rgba(111, 191, 115, 0.2);
|
|
100
|
+
border: 1px solid rgba(111, 191, 115, 0.4);
|
|
101
|
+
color: lighten($accent-green, 20%);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
&.alert-danger {
|
|
105
|
+
background-color: rgba(251, 73, 52, 0.2);
|
|
106
|
+
border: 1px solid rgba(251, 73, 52, 0.4);
|
|
107
|
+
color: lighten(#fb4934, 20%);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ===========================
|
|
113
|
+
// Full Page Newsletter Forms
|
|
114
|
+
// ===========================
|
|
115
|
+
.newsletter-page-container {
|
|
116
|
+
max-width: 800px;
|
|
117
|
+
margin: 0 auto;
|
|
118
|
+
padding: $spacing-xl;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.newsletter-section {
|
|
122
|
+
margin-bottom: $spacing-xxl;
|
|
123
|
+
|
|
124
|
+
&:last-child {
|
|
125
|
+
margin-bottom: 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.newsletter-section-title {
|
|
129
|
+
font-size: $xlarge-font-size;
|
|
130
|
+
font-weight: $bold-weight;
|
|
131
|
+
color: $dark-white;
|
|
132
|
+
margin-bottom: $spacing-md;
|
|
133
|
+
padding-bottom: $spacing-md;
|
|
134
|
+
border-bottom: 2px solid rgba(138, 168, 255, 0.2);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.newsletter-section-description {
|
|
138
|
+
font-size: $base-font-size;
|
|
139
|
+
color: $darker-white;
|
|
140
|
+
margin-bottom: $spacing-lg;
|
|
141
|
+
line-height: $base-line-height;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Newsletter form specific styling (subscribe, unsubscribe, status check)
|
|
146
|
+
#newsletterSubscribeForm,
|
|
147
|
+
#newsletterUnsubscribeForm,
|
|
148
|
+
#newsletterStatusForm {
|
|
149
|
+
max-width: 600px;
|
|
150
|
+
margin: 0 auto;
|
|
151
|
+
|
|
152
|
+
.form-control {
|
|
153
|
+
margin-bottom: $spacing-lg;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.form-buttons {
|
|
157
|
+
display: flex;
|
|
158
|
+
flex-direction: column;
|
|
159
|
+
gap: $spacing-md;
|
|
160
|
+
margin-top: $spacing-md;
|
|
161
|
+
|
|
162
|
+
.btn {
|
|
163
|
+
width: 100%;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Single button (not in .form-buttons)
|
|
168
|
+
.btn:not(.form-buttons .btn) {
|
|
169
|
+
width: 100%;
|
|
170
|
+
margin-top: $spacing-md;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Alert messages
|
|
174
|
+
.alert {
|
|
175
|
+
margin-top: $spacing-lg;
|
|
176
|
+
padding: $spacing-md;
|
|
177
|
+
border-radius: 8px;
|
|
178
|
+
font-weight: $medium-weight;
|
|
179
|
+
|
|
180
|
+
&.alert-success {
|
|
181
|
+
background-color: rgba(111, 191, 115, 0.2);
|
|
182
|
+
border: 1px solid rgba(111, 191, 115, 0.4);
|
|
183
|
+
color: lighten($accent-green, 20%);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
&.alert-danger {
|
|
187
|
+
background-color: rgba(251, 73, 52, 0.2);
|
|
188
|
+
border: 1px solid rgba(251, 73, 52, 0.4);
|
|
189
|
+
color: lighten(#fb4934, 20%);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
&.alert-info {
|
|
193
|
+
background-color: rgba(138, 168, 255, 0.2);
|
|
194
|
+
border: 1px solid rgba(138, 168, 255, 0.4);
|
|
195
|
+
color: lighten($darker-text-link-blue, 20%);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Status check result display
|
|
201
|
+
.newsletter-status-result {
|
|
202
|
+
margin-top: $spacing-lg;
|
|
203
|
+
padding: $spacing-lg;
|
|
204
|
+
background: rgba(27, 29, 37, 0.5);
|
|
205
|
+
border: 1px solid rgba(138, 168, 255, 0.2);
|
|
206
|
+
border-radius: 12px;
|
|
207
|
+
backdrop-filter: blur(8px);
|
|
208
|
+
-webkit-backdrop-filter: blur(8px);
|
|
209
|
+
|
|
210
|
+
.status-row {
|
|
211
|
+
display: flex;
|
|
212
|
+
justify-content: space-between;
|
|
213
|
+
align-items: center;
|
|
214
|
+
padding: $spacing-sm 0;
|
|
215
|
+
border-bottom: 1px solid rgba(138, 168, 255, 0.1);
|
|
216
|
+
|
|
217
|
+
&:last-child {
|
|
218
|
+
border-bottom: none;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.status-label {
|
|
222
|
+
font-weight: $semibold-weight;
|
|
223
|
+
color: $darker-white;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.status-value {
|
|
227
|
+
color: $dark-white;
|
|
228
|
+
|
|
229
|
+
&.status-active {
|
|
230
|
+
color: lighten($accent-green, 20%);
|
|
231
|
+
font-weight: $semibold-weight;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
&.status-inactive {
|
|
235
|
+
color: lighten(#fb4934, 20%);
|
|
236
|
+
font-weight: $semibold-weight;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
&.status-not-found {
|
|
240
|
+
color: $darker-white;
|
|
241
|
+
font-style: italic;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Mobile responsiveness
|
|
248
|
+
@media (max-width: 575px) {
|
|
249
|
+
.newsletter-footer-signup {
|
|
250
|
+
.newsletter-title {
|
|
251
|
+
font-size: $medium-font-size;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.newsletter-description {
|
|
255
|
+
font-size: $small-font-size;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.newsletter-input-group {
|
|
259
|
+
gap: $spacing-sm;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.newsletter-page-container {
|
|
264
|
+
padding: $spacing-md;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.newsletter-section {
|
|
268
|
+
.newsletter-section-title {
|
|
269
|
+
font-size: $large-font-size;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jscom_ice
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- John Sosoka
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-10-
|
|
11
|
+
date: 2025-10-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: jekyll
|
|
@@ -82,6 +82,10 @@ files:
|
|
|
82
82
|
- _includes/header.html
|
|
83
83
|
- _includes/john_landing.html
|
|
84
84
|
- _includes/navbar.html
|
|
85
|
+
- _includes/newsletter-signup-footer.html
|
|
86
|
+
- _includes/newsletter-status-check.html
|
|
87
|
+
- _includes/newsletter-subscribe-form.html
|
|
88
|
+
- _includes/newsletter-unsubscribe-form.html
|
|
85
89
|
- _includes/post_navigation.html
|
|
86
90
|
- _includes/posts.html
|
|
87
91
|
- _includes/scripts.html
|
|
@@ -103,6 +107,7 @@ files:
|
|
|
103
107
|
- _sass/component/_github-gist.scss
|
|
104
108
|
- _sass/component/_highlight.scss
|
|
105
109
|
- _sass/component/_navbar.scss
|
|
110
|
+
- _sass/component/_newsletter.scss
|
|
106
111
|
- _sass/component/_post-navigation.scss
|
|
107
112
|
- _sass/component/_posts.scss
|
|
108
113
|
- _sass/component/_table.scss
|