feat: add newsletter signup section to landing page
Adds a Listmonk-powered newsletter form at the bottom of the rSpace landing page, matching the dark theme and gradient styling of existing sections. Uses rSpace list UUID for subscriber routing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
91d600ed93
commit
095d6e1eb9
|
|
@ -285,7 +285,66 @@
|
||||||
border-color: rgba(124, 58, 237, 0.6);
|
border-color: rgba(124, 58, 237, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Newsletter */
|
||||||
|
.newsletter-form {
|
||||||
|
max-width: 440px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newsletter-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newsletter-input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
color: white;
|
||||||
|
font-size: 1rem;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newsletter-input:focus {
|
||||||
|
border-color: #14b8a6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newsletter-input::placeholder {
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newsletter-btn {
|
||||||
|
padding: 12px 24px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newsletter-status {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
min-height: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newsletter-status.success {
|
||||||
|
color: #22c55e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newsletter-status.error {
|
||||||
|
color: #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newsletter-privacy {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #64748b;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
|
.newsletter-row {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
.pillars {
|
.pillars {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
@ -517,6 +576,29 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-divider"></div>
|
||||||
|
<h2>Stay Connected</h2>
|
||||||
|
<p class="section-subtitle">
|
||||||
|
Get updates on rSpace development, new ecosystem modules, and community features.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form class="newsletter-form" id="newsletter-form">
|
||||||
|
<div class="newsletter-row">
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
id="newsletter-email"
|
||||||
|
placeholder="your@email.com"
|
||||||
|
required
|
||||||
|
class="newsletter-input"
|
||||||
|
/>
|
||||||
|
<button type="submit" class="newsletter-btn" id="newsletter-btn">Subscribe</button>
|
||||||
|
</div>
|
||||||
|
<p class="newsletter-status" id="newsletter-status"></p>
|
||||||
|
<p class="newsletter-privacy">No spam, unsubscribe anytime.</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { RStackIdentity } from "@shared/components/rstack-identity";
|
import { RStackIdentity } from "@shared/components/rstack-identity";
|
||||||
import { RStackAppSwitcher } from "@shared/components/rstack-app-switcher";
|
import { RStackAppSwitcher } from "@shared/components/rstack-app-switcher";
|
||||||
|
|
@ -529,6 +611,48 @@
|
||||||
fetch("/api/modules").then(r => r.json()).then(data => {
|
fetch("/api/modules").then(r => r.json()).then(data => {
|
||||||
document.querySelector("rstack-app-switcher")?.setModules(data.modules || []);
|
document.querySelector("rstack-app-switcher")?.setModules(data.modules || []);
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
|
|
||||||
|
// Newsletter signup
|
||||||
|
const newsletterForm = document.getElementById("newsletter-form");
|
||||||
|
const newsletterEmail = document.getElementById("newsletter-email");
|
||||||
|
const newsletterBtn = document.getElementById("newsletter-btn");
|
||||||
|
const newsletterStatus = document.getElementById("newsletter-status");
|
||||||
|
|
||||||
|
newsletterForm.addEventListener("submit", async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const email = newsletterEmail.value.trim();
|
||||||
|
if (!email) return;
|
||||||
|
|
||||||
|
newsletterBtn.disabled = true;
|
||||||
|
newsletterBtn.textContent = "Subscribing...";
|
||||||
|
newsletterStatus.textContent = "";
|
||||||
|
newsletterStatus.className = "newsletter-status";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch("https://newsletter.jeffemmett.com/subscribe", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
email,
|
||||||
|
list_uuid: "2d247234-34cf-4ee6-858f-2b5e24e2e5dc",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
newsletterStatus.textContent = "Welcome to the network. The space expands.";
|
||||||
|
newsletterStatus.className = "newsletter-status success";
|
||||||
|
newsletterEmail.value = "";
|
||||||
|
} else {
|
||||||
|
throw new Error("Subscription failed");
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
newsletterStatus.textContent = "Something went wrong. Please try again.";
|
||||||
|
newsletterStatus.className = "newsletter-status error";
|
||||||
|
} finally {
|
||||||
|
newsletterBtn.disabled = false;
|
||||||
|
newsletterBtn.textContent = "Subscribe";
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue