Skip to content

Commit ff0f30d

Browse files
Edwin ChanEdwin Chan
authored andcommitted
greetings settings
1 parent 6a2fe25 commit ff0f30d

2 files changed

Lines changed: 128 additions & 13 deletions

File tree

app/settings/page.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ export default function SettingsPage() {
6969
const [error, setError] = useState<string | null>(null);
7070
const [success, setSuccess] = useState<string | null>(null);
7171
const [loading, setLoading] = useState(true);
72+
const [typewriterSettings, setTypewriterSettings] = useState({
73+
typeSpeed: 42,
74+
deleteSpeed: 22,
75+
holdMs: 3676,
76+
betweenMs: 280,
77+
});
7278
const themePreference = useSyncExternalStore<ThemePreference>(
7379
subscribeThemePreference,
7480
getThemeSnapshot,
@@ -113,6 +119,13 @@ export default function SettingsPage() {
113119
})
114120
.catch(() => setError("Failed to load profile."))
115121
.finally(() => setLoading(false));
122+
123+
try {
124+
const storedThemeSettings = localStorage.getItem("mo-typewriter-settings");
125+
if (storedThemeSettings) {
126+
setTypewriterSettings((prev) => ({ ...prev, ...JSON.parse(storedThemeSettings) }));
127+
}
128+
} catch {}
116129
}, []);
117130

118131
useEffect(() => {
@@ -127,6 +140,18 @@ export default function SettingsPage() {
127140
setError(null);
128141
setSuccess(null);
129142
setSaving(true);
143+
144+
try {
145+
const parsedTypewriter = {
146+
typeSpeed: Math.max(10, Math.min(500, Number(typewriterSettings.typeSpeed) || 42)),
147+
deleteSpeed: Math.max(10, Math.min(500, Number(typewriterSettings.deleteSpeed) || 22)),
148+
holdMs: Math.max(500, Math.min(15000, Number(typewriterSettings.holdMs) || 3676)),
149+
betweenMs: Math.max(100, Math.min(5000, Number(typewriterSettings.betweenMs) || 280)),
150+
};
151+
localStorage.setItem("mo-typewriter-settings", JSON.stringify(parsedTypewriter));
152+
setTypewriterSettings(parsedTypewriter);
153+
window.dispatchEvent(new Event("storage"));
154+
} catch {}
130155

131156
try {
132157
const res = await fetch("/api/settings", {
@@ -328,6 +353,54 @@ export default function SettingsPage() {
328353
<small className="form-hint">Saved on this browser.</small>
329354
</div>
330355

356+
<div className="settings-row">
357+
<label>Greeting Typing Speed (ms)</label>
358+
<input
359+
type="number"
360+
min="10"
361+
max="500"
362+
value={typewriterSettings.typeSpeed}
363+
onChange={(e) => setTypewriterSettings({ ...typewriterSettings, typeSpeed: Number(e.target.value) })}
364+
/>
365+
<small className="form-hint">Time between typing each character. Default: 42</small>
366+
</div>
367+
368+
<div className="settings-row">
369+
<label>Greeting Deleting Speed (ms)</label>
370+
<input
371+
type="number"
372+
min="10"
373+
max="500"
374+
value={typewriterSettings.deleteSpeed}
375+
onChange={(e) => setTypewriterSettings({ ...typewriterSettings, deleteSpeed: Number(e.target.value) })}
376+
/>
377+
<small className="form-hint">Time between deleting each character. Default: 22</small>
378+
</div>
379+
380+
<div className="settings-row">
381+
<label>Greeting Hold Time (ms)</label>
382+
<input
383+
type="number"
384+
min="500"
385+
max="15000"
386+
value={typewriterSettings.holdMs}
387+
onChange={(e) => setTypewriterSettings({ ...typewriterSettings, holdMs: Number(e.target.value) })}
388+
/>
389+
<small className="form-hint">Read time before deleting. Default: 3676</small>
390+
</div>
391+
392+
<div className="settings-row">
393+
<label>Time Between Greetings (ms)</label>
394+
<input
395+
type="number"
396+
min="100"
397+
max="5000"
398+
value={typewriterSettings.betweenMs}
399+
onChange={(e) => setTypewriterSettings({ ...typewriterSettings, betweenMs: Number(e.target.value) })}
400+
/>
401+
<small className="form-hint">Pause before the next greeting starts. Default: 280</small>
402+
</div>
403+
331404
<div className="settings-row">
332405
<label>Privacy</label>
333406
<div className="settings-toggle-list">

app/typewriter-greeting.tsx

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,43 @@
22

33
import { useEffect, useMemo, useState } from "react";
44

5-
const TYPE_SPEED_MS = 42;
6-
const DELETE_SPEED_MS = 22;
7-
const HOLD_MS = 3676;
8-
const BETWEEN_GREETING_MS = 280;
5+
const DEFAULT_TYPE_SPEED_MS = 42;
6+
const DEFAULT_DELETE_SPEED_MS = 22;
7+
const DEFAULT_HOLD_MS = 3676;
8+
const DEFAULT_BETWEEN_GREETING_MS = 280;
99

1010
const GREETINGS = [
1111
(name: string) => `Hello, ${name}!`,
12+
(name: string) => `${name}, your working is correct but the answer is wrong.`,
1213
(name: string) => `Eat more curry, ${name}!`,
1314
(name: string) => `Subscribe to Let's Think Critically, ${name}!`,
15+
(name: string) => `${name}, have you tried turning your brain off and on again?`,
1416
(name: string) => `Welcome back, ${name}.`,
1517
(name: string) => `Wassup :), ${name}.`,
16-
(name: string) => `Good to see you, ${name}.`,
17-
(name: string) => `Make me proud, ${name}.`,
1818
(name: string) => `Be Culver Kwan, ${name}.`,
1919
(name: string) => `Time to lock in, ${name}.`,
20-
(name: string) => `Be Marcoroni :3, ${name}.`,
2120
(name: string) => `Marcoroni is typing..., ${name}.`,
2221
(name: string) => `Search Marco The Dog, ${name}.`,
2322
(name: string) => `Be more ORZ, ${name}.`,
2423
(name: string) => `Solve these problems if you're not gay, ${name}.`,
2524
(name: string) => `${name}! Stay determined!`,
26-
() => `Nature is written in mathematical language.`,
27-
() => `In mathematics, you don’t understand things. You just get used to them.`,
2825
(name: string) => `${name}, you forgot a ± somewhere.`,
2926
(name: string) => `${name}, you look like a trapezium.`,
27+
() => `Just cancel the dx's. Trust me.`,
28+
() => `Proof left as an exercise to the reader.`,
29+
() => `Step 1: Draw a circle. Step 2: ???. Step 3: Proof complete.`,
3030
() => `The Riemann Hypothesis has been solved!`,
3131
() => `I still remember the thrill of solving my first integral.`,
32+
(name: string) => `${name} divided by 0. Error.`,
3233
() => `Numbers don't lie.`,
3334
() => `Is it always true? Sometimes true? Or never true?`,
3435
(name: string) => `${name}, WAKE UP!`,
35-
() => `lim h->0 f(x+h) - f(x) / h`,
36+
() => `sin(x) = x. QED.`,
37+
() => `It is trivially obvious that 0 = 1. QED.`,
3638
(name: string) => `${name}" or 1 = 1 --`,
3739
() => `Take pi = 3`,
3840
() => `Eat. Sleep. Math. Repeat.`,
41+
(name: string) => `Initialising ${name}... please wait... still waiting...stillllllll waiting...`,
3942
];
4043

4144
const getRandomGreetingIndex = (exclude?: number) => {
@@ -52,18 +55,57 @@ function GreetingTyper({ name }: { name: string }) {
5255
const [greetingIndex, setGreetingIndex] = useState(() => getRandomGreetingIndex());
5356
const [charIndex, setCharIndex] = useState(0);
5457
const [isDeleting, setIsDeleting] = useState(false);
58+
const [speeds, setSpeeds] = useState({
59+
typeSpeed: DEFAULT_TYPE_SPEED_MS,
60+
deleteSpeed: DEFAULT_DELETE_SPEED_MS,
61+
holdMs: DEFAULT_HOLD_MS,
62+
betweenMs: DEFAULT_BETWEEN_GREETING_MS,
63+
});
64+
65+
useEffect(() => {
66+
try {
67+
const stored = localStorage.getItem("mo-typewriter-settings");
68+
if (stored) {
69+
const parsed = JSON.parse(stored);
70+
setSpeeds({
71+
typeSpeed: Math.max(10, Math.min(500, Number(parsed.typeSpeed) || DEFAULT_TYPE_SPEED_MS)),
72+
deleteSpeed: Math.max(10, Math.min(500, Number(parsed.deleteSpeed) || DEFAULT_DELETE_SPEED_MS)),
73+
holdMs: Math.max(500, Math.min(15000, Number(parsed.holdMs) || DEFAULT_HOLD_MS)),
74+
betweenMs: Math.max(100, Math.min(5000, Number(parsed.betweenMs) || DEFAULT_BETWEEN_GREETING_MS)),
75+
});
76+
}
77+
} catch {}
78+
79+
const handleStorage = () => {
80+
try {
81+
const stored = localStorage.getItem("mo-typewriter-settings");
82+
if (stored) {
83+
const parsed = JSON.parse(stored);
84+
setSpeeds({
85+
typeSpeed: Math.max(10, Math.min(500, Number(parsed.typeSpeed) || DEFAULT_TYPE_SPEED_MS)),
86+
deleteSpeed: Math.max(10, Math.min(500, Number(parsed.deleteSpeed) || DEFAULT_DELETE_SPEED_MS)),
87+
holdMs: Math.max(500, Math.min(15000, Number(parsed.holdMs) || DEFAULT_HOLD_MS)),
88+
betweenMs: Math.max(100, Math.min(5000, Number(parsed.betweenMs) || DEFAULT_BETWEEN_GREETING_MS)),
89+
});
90+
}
91+
} catch {}
92+
};
93+
94+
window.addEventListener("storage", handleStorage);
95+
return () => window.removeEventListener("storage", handleStorage);
96+
}, []);
5597

5698
const activeGreeting = useMemo(() => GREETINGS[greetingIndex](name), [greetingIndex, name]);
5799

58100
useEffect(() => {
59-
let delay = isDeleting ? DELETE_SPEED_MS : TYPE_SPEED_MS;
101+
let delay = isDeleting ? speeds.deleteSpeed : speeds.typeSpeed;
60102

61103
if (!isDeleting && charIndex === activeGreeting.length) {
62-
delay = HOLD_MS;
104+
delay = speeds.holdMs;
63105
}
64106

65107
if (isDeleting && charIndex === 0) {
66-
delay = BETWEEN_GREETING_MS;
108+
delay = speeds.betweenMs;
67109
}
68110

69111
const timer = window.setTimeout(() => {

0 commit comments

Comments
 (0)