forked from keodotcomputer/keodotcomputer.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
123 lines (116 loc) · 4.22 KB
/
script.js
File metadata and controls
123 lines (116 loc) · 4.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Theme toggle (sets a data-theme on <html>)
(function () {
const root = document.documentElement;
const toggle = document.querySelector(".theme-toggle");
const saved = localStorage.getItem("theme");
function applyTheme(t) {
root.setAttribute("data-theme", t);
}
applyTheme(saved || "dark");
toggle.addEventListener("click", () => {
const next = root.getAttribute("data-theme") === "dark" ? "light" : "dark";
applyTheme(next);
localStorage.setItem("theme", next);
toggle.textContent = next === "dark" ? "🌙" : "☀️";
});
// set initial icon
toggle.textContent =
document.documentElement.getAttribute("data-theme") === "dark"
? "🌙"
: "☀️";
// set year
document.getElementById("year").textContent = new Date().getFullYear();
// Newsletter form handling: posts to Formspree (replace action URL with your form endpoint)
const form = document.getElementById("newsletter-form");
if (form) {
form.addEventListener("submit", async (ev) => {
ev.preventDefault();
const msg = document.getElementById("newsletter-msg");
const email = form.querySelector('input[name="email"]')?.value?.trim();
if (!email || !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) {
msg.textContent = "Please enter a valid email address.";
msg.className = "newsletter-msg error";
return;
}
msg.textContent = "Sending…";
msg.className = "newsletter-msg";
// Try to POST via fetch to the form action. If user hasn't configured a service, fall back to a local save.
const action = form.getAttribute("action");
try {
const res = await fetch(action, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
});
if (res.ok) {
msg.textContent = "Thanks — you are subscribed!";
msg.className = "newsletter-msg success";
form.reset();
return;
}
// non-OK response: try to parse JSON for error message
let data;
try {
data = await res.json();
} catch (e) {}
msg.textContent =
data && data.error
? data.error
: "Submission failed. Please try again later.";
msg.className = "newsletter-msg error";
} catch (err) {
// fallback: save locally and show success message so the UX isn't broken.
try {
const stored = JSON.parse(
localStorage.getItem("newsletter-signups") || "[]"
);
stored.push({ email: email, when: new Date().toISOString() });
localStorage.setItem("newsletter-signups", JSON.stringify(stored));
msg.textContent =
"Saved locally — replace the form action with a mailing-service endpoint to enable real signups.";
msg.className = "newsletter-msg success";
form.reset();
} catch (e2) {
msg.textContent = "Could not save signup. Please try again later.";
msg.className = "newsletter-msg error";
}
}
});
}
})()(
// Random twinkling star that moves in a fixed radius
(function () {
const radius = 80; // pixels
const baseX = window.innerWidth * 0.2;
const baseY = window.innerHeight * 3;
function getRandomPosition() {
const angle = Math.random() * Math.PI * 2;
const distance = Math.random() * radius;
return {
x: baseX + Math.cos(angle) * distance,
y: baseY + Math.sin(angle) * distance,
};
}
function updateStar() {
const pos = getRandomPosition();
const opacity = 0.3 + Math.random() * 0.7;
const duration = 1 + Math.random() * 2;
document.documentElement.style.setProperty("--star-x", pos.x + "px");
document.documentElement.style.setProperty("--star-y", pos.y + "px");
document.documentElement.style.setProperty("--star-opacity", opacity);
document.documentElement.style.setProperty(
"--star-duration",
duration + "s"
);
}
// Initial position
updateStar();
// Update every 2-4 seconds
setInterval(() => {
updateStar();
}, 2000 + Math.random() * 2000);
})()
);