From 9d9749f00cb5d1453414611b8d4feb4ddb2d5de5 Mon Sep 17 00:00:00 2001 From: davidasix Date: Sun, 11 Jan 2026 14:56:54 -0500 Subject: [PATCH 01/14] Add pasted Loops form --- src/app/_components/loops-waitlist-form.tsx | 290 ++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 src/app/_components/loops-waitlist-form.tsx diff --git a/src/app/_components/loops-waitlist-form.tsx b/src/app/_components/loops-waitlist-form.tsx new file mode 100644 index 0000000..16fc53c --- /dev/null +++ b/src/app/_components/loops-waitlist-form.tsx @@ -0,0 +1,290 @@ +import { useState } from "react"; + +const INIT = "INIT"; +const SUBMITTING = "SUBMITTING"; +const ERROR = "ERROR"; +const SUCCESS = "SUCCESS"; +const formStates = [INIT, SUBMITTING, ERROR, SUCCESS] as const; +const formStyles = { + id: "cmka5bpaq4l9n0iyohs0tlush", + name: "Default", + formStyle: "inline", + placeholderText: "you@example.com", + formFont: "Open Sans", + formFontColor: "#000000", + formFontSizePx: 14, + buttonText: "Join Waitlist", + buttonFont: "Inter", + buttonFontColor: "#ffffff", + buttonColor: "#0D9488", + buttonFontSizePx: 14, + successMessage: "Thanks! We'll be in touch!", + successFont: "Inter", + successFontColor: "#ff0000", + successFontSizePx: 14, + userGroup: "waitlist", + team: { + mailingLists: [], + }, +}; +const domain = "app.loops.so"; + +export default function SignUpFormReact() { + const [email, setEmail] = useState(""); + const [formState, setFormState] = useState<(typeof formStates)[number]>(INIT); + const [errorMessage, setErrorMessage] = useState(""); + const [fields, setFields] = useState({}); + + const resetForm = () => { + setEmail(""); + setFormState(INIT); + setErrorMessage(""); + }; + + /** + * Rate limit the number of submissions allowed + * @returns {boolean} true if the form has been successfully submitted in the past minute + */ + const hasRecentSubmission = () => { + const time = new Date(); + const timestamp = time.valueOf(); + const previousTimestamp = localStorage.getItem("loops-form-timestamp"); + + // Indicate if the last sign up was less than a minute ago + if ( + previousTimestamp && + Number(previousTimestamp) + 60 * 1000 > timestamp + ) { + setFormState(ERROR); + setErrorMessage("Too many signups, please try again in a little while"); + return true; + } + + localStorage.setItem("loops-form-timestamp", timestamp.toString()); + return false; + }; + + const handleSubmit = (event: React.FormEvent) => { + // Prevent the default form submission + event.preventDefault(); + + // boundary conditions for submission + if (formState !== INIT) return; + if (!isValidEmail(email)) { + setFormState(ERROR); + setErrorMessage("Please enter a valid email"); + return; + } + if (hasRecentSubmission()) return; + setFormState(SUBMITTING); + + // build additional fields + const additionalFields = Object.entries(fields).reduce( + (acc, [key, val]) => { + if (val) { + return acc + "&" + key + "=" + encodeURIComponent(val); + } + return acc; + }, + "", + ); + + // build body + const formBody = `userGroup=${encodeURIComponent( + formStyles.userGroup, + )}&email=${encodeURIComponent(email)}&mailingLists=`; + + // API request to add user to newsletter + fetch(`https://${domain}/api/newsletter-form/${formStyles.id}`, { + method: "POST", + body: formBody + additionalFields, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + }) + .then((res: any) => [res.ok, res.json(), res]) + .then(([ok, dataPromise, res]) => { + if (ok) { + resetForm(); + setFormState(SUCCESS); + } else { + dataPromise.then((data: any) => { + setFormState(ERROR); + setErrorMessage(data.message || res.statusText); + localStorage.setItem("loops-form-timestamp", ""); + }); + } + }) + .catch((error) => { + setFormState(ERROR); + // check for cloudflare error + if (error.message === "Failed to fetch") { + setErrorMessage( + "Too many signups, please try again in a little while", + ); + } else if (error.message) { + setErrorMessage(error.message); + } + localStorage.setItem("loops-form-timestamp", ""); + }); + }; + + const isInline = formStyles.formStyle === "inline"; + + switch (formState) { + case SUCCESS: + return ( +
+

+ {formStyles.successMessage} +

+
+ ); + case ERROR: + return ( + <> + + + + ); + default: + return ( + <> +
+ setEmail(e.target.value)} + required={true} + style={{ + color: formStyles.formFontColor, + fontFamily: `'${formStyles.formFont}', sans-serif`, + fontSize: `${formStyles.formFontSizePx}px`, + margin: isInline ? "0px 10px 0px 0px" : "0px 0px 10px", + width: "100%", + maxWidth: "300px", + minWidth: "100px", + background: "#FFFFFF", + border: "1px solid #D1D5DB", + boxSizing: "border-box", + boxShadow: "rgba(0, 0, 0, 0.05) 0px 1px 2px", + borderRadius: "6px", + padding: "8px 12px", + }} + /> + + + + + ); + } + + function SignUpFormError() { + return ( +
+

+ {errorMessage || "Oops! Something went wrong, please try again"} +

+
+ ); + } + + function BackButton() { + const [isHovered, setIsHovered] = useState(false); + + return ( + + ); + } + + function SignUpFormButton({ props }: any) { + return ( + + ); + } +} + +function isValidEmail(email: any) { + return /.+@.+/.test(email); +} From 2de64bac6048bc65a5859760c87d43827ceb71e6 Mon Sep 17 00:00:00 2001 From: davidasix Date: Sun, 11 Jan 2026 15:03:57 -0500 Subject: [PATCH 02/14] Replace with ShadCN and custom styling components --- src/app/_components/loops-waitlist-form.tsx | 171 +++++--------------- 1 file changed, 42 insertions(+), 129 deletions(-) diff --git a/src/app/_components/loops-waitlist-form.tsx b/src/app/_components/loops-waitlist-form.tsx index 16fc53c..9d7a091 100644 --- a/src/app/_components/loops-waitlist-form.tsx +++ b/src/app/_components/loops-waitlist-form.tsx @@ -1,4 +1,8 @@ +"use client"; + import { useState } from "react"; +import { Button } from "~/components/ui/button"; +import { Input } from "~/components/ui/input"; const INIT = "INIT"; const SUBMITTING = "SUBMITTING"; @@ -10,18 +14,8 @@ const formStyles = { name: "Default", formStyle: "inline", placeholderText: "you@example.com", - formFont: "Open Sans", - formFontColor: "#000000", - formFontSizePx: 14, buttonText: "Join Waitlist", - buttonFont: "Inter", - buttonFontColor: "#ffffff", - buttonColor: "#0D9488", - buttonFontSizePx: 14, successMessage: "Thanks! We'll be in touch!", - successFont: "Inter", - successFontColor: "#ff0000", - successFontSizePx: 14, userGroup: "waitlist", team: { mailingLists: [], @@ -33,7 +27,7 @@ export default function SignUpFormReact() { const [email, setEmail] = useState(""); const [formState, setFormState] = useState<(typeof formStates)[number]>(INIT); const [errorMessage, setErrorMessage] = useState(""); - const [fields, setFields] = useState({}); + const [fields, setFields] = useState>({}); const resetForm = () => { setEmail(""); @@ -102,20 +96,20 @@ export default function SignUpFormReact() { "Content-Type": "application/x-www-form-urlencoded", }, }) - .then((res: any) => [res.ok, res.json(), res]) + .then((res) => [res.ok, res.json(), res] as const) .then(([ok, dataPromise, res]) => { if (ok) { resetForm(); setFormState(SUCCESS); } else { - dataPromise.then((data: any) => { + dataPromise.then((data: { message?: string }) => { setFormState(ERROR); - setErrorMessage(data.message || res.statusText); + setErrorMessage(data.message ?? res.statusText); localStorage.setItem("loops-form-timestamp", ""); }); } }) - .catch((error) => { + .catch((error: Error) => { setFormState(ERROR); // check for cloudflare error if (error.message === "Failed to fetch") { @@ -134,94 +128,44 @@ export default function SignUpFormReact() { switch (formState) { case SUCCESS: return ( -
-

+

+

{formStyles.successMessage}

); case ERROR: return ( - <> +
- +
); default: return ( - <> -
- setEmail(e.target.value)} - required={true} - style={{ - color: formStyles.formFontColor, - fontFamily: `'${formStyles.formFont}', sans-serif`, - fontSize: `${formStyles.formFontSizePx}px`, - margin: isInline ? "0px 10px 0px 0px" : "0px 0px 10px", - width: "100%", - maxWidth: "300px", - minWidth: "100px", - background: "#FFFFFF", - border: "1px solid #D1D5DB", - boxSizing: "border-box", - boxShadow: "rgba(0, 0, 0, 0.05) 0px 1px 2px", - borderRadius: "6px", - padding: "8px 12px", - }} - /> - - - - +
+ setEmail(e.target.value)} + required + className="w-full max-w-xs" + /> +
@@ -44,20 +44,20 @@ export function Footer() { More
- Privacy Policy - - */} + Built by davidasix - +
diff --git a/src/components/navigation.tsx b/src/components/navigation.tsx index 2a33cea..4ce8ae1 100644 --- a/src/components/navigation.tsx +++ b/src/components/navigation.tsx @@ -62,12 +62,12 @@ export function Navigation() { {/* Desktop Navigation */}
- Practice - + */} {/* Theme Toggle */} {mounted && ( @@ -86,7 +86,7 @@ export function Navigation() { )} {/* Auth Section */} - {session ? ( + {/* {session ? ( @@ -110,7 +110,7 @@ export function Navigation() { - )} + )} */}
{/* Mobile Menu Button */} @@ -131,7 +131,7 @@ export function Navigation() { )} - + */} {/* Mobile Menu */} - {isMobileMenuOpen && ( + {/* {isMobileMenuOpen && (
- )} + )} */}
); From 1f778c95e5182d94d96402b6d1a41acd1856e762 Mon Sep 17 00:00:00 2001 From: davidasix Date: Sun, 18 Jan 2026 16:35:27 -0500 Subject: [PATCH 06/14] Button style cleanup --- src/components/ui/button.tsx | 8 ++++---- src/styles/globals.css | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index c5b1f25..71cb6bd 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -21,10 +21,10 @@ const buttonVariants = cva( }, size: { default: - "h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5", - xs: "h-6 gap-1 px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3", - sm: "h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2", - lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3", + "h-10 gap-1.5 px-10 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5", + xs: "h-6 gap-1 px-6 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3", + sm: "h-8 gap-1 px-8 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2", + lg: "h-12 gap-1.5 px-12 text-lg has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3", icon: "size-9", "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3", "icon-sm": "size-8", diff --git a/src/styles/globals.css b/src/styles/globals.css index 66b3e30..dec9dcd 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -169,10 +169,10 @@ transform: rotate(0deg); } 25% { - transform: rotate(-2deg); + transform: rotate(-0.25deg); } 75% { - transform: rotate(2deg); + transform: rotate(0.25deg); } } From 6defd5e50dd6a6b5cbf0d86599f71c9187bc45bb Mon Sep 17 00:00:00 2001 From: davidasix Date: Sun, 18 Jan 2026 16:35:56 -0500 Subject: [PATCH 07/14] Page cleanup --- src/app/_components/loops-waitlist-form.tsx | 3 +-- src/app/page.tsx | 29 ++++++++++++--------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/app/_components/loops-waitlist-form.tsx b/src/app/_components/loops-waitlist-form.tsx index 9d7a091..f424634 100644 --- a/src/app/_components/loops-waitlist-form.tsx +++ b/src/app/_components/loops-waitlist-form.tsx @@ -23,7 +23,7 @@ const formStyles = { }; const domain = "app.loops.so"; -export default function SignUpFormReact() { +export default function WaitListForm() { const [email, setEmail] = useState(""); const [formState, setFormState] = useState<(typeof formStates)[number]>(INIT); const [errorMessage, setErrorMessage] = useState(""); @@ -190,7 +190,6 @@ export default function SignUpFormReact() { diff --git a/src/app/page.tsx b/src/app/page.tsx index 2708d87..8b68698 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,7 +1,7 @@ import Link from "next/link"; import Image from "next/image"; import { Clock, TrendingUp, Sparkles, Star } from "lucide-react"; -import { Button } from "~/components/ui/button"; +import { buttonVariants } from "~/components/ui/button"; import { Card, CardDescription, @@ -10,7 +10,8 @@ import { } from "~/components/ui/card"; import { Badge } from "~/components/ui/badge"; import { HydrateClient } from "~/trpc/server"; -import SignUpFormReact from "~/app/_components/loops-waitlist-form"; +import WaitListForm from "~/app/_components/loops-waitlist-form"; +import { cn } from "~/lib/utils"; export default async function Home() { return ( @@ -27,11 +28,12 @@ export default async function Home() { Practice table-topics and hone your skills. Track your progress and build confidence with timed speaking sessions.

-
- - +
+ + Get Started
@@ -60,10 +62,10 @@ export default async function Home() { Join the Waitlist

- Be the first to know when we launch new features and updates. + Be the first to know when we launch TableTopicker

- +
@@ -176,10 +178,11 @@ export default async function Home() { something you should practice. - - + + Get Started From 5db067b7e76fa71e41a7517708136174a0d74b15 Mon Sep 17 00:00:00 2001 From: davidasix Date: Sun, 18 Jan 2026 16:41:13 -0500 Subject: [PATCH 08/14] Add favicon --- public/favicon.ico | Bin 15406 -> 1460 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/favicon.ico b/public/favicon.ico index 60c702aac13409c82c4040f8fee9603eb84aa10c..7b04c9bfbd7adf85a6e207d59145d5d6847b400e 100644 GIT binary patch literal 1460 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 A#Q*>R From cac4cc7ad4416f9f89eb013c2bce754b8b107046 Mon Sep 17 00:00:00 2001 From: davidasix Date: Sun, 18 Jan 2026 16:43:45 -0500 Subject: [PATCH 09/14] Add 404 page --- src/app/not-found.tsx | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/app/not-found.tsx diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx new file mode 100644 index 0000000..f4ac12e --- /dev/null +++ b/src/app/not-found.tsx @@ -0,0 +1,44 @@ +import Link from "next/link"; +import Image from "next/image"; +import { buttonVariants } from "~/components/ui/button"; +import { cn } from "~/lib/utils"; + +export default function NotFound() { + return ( +
+
+
+
+ Mikey the microphone mascot looking confused +
+
+ +

+ 404 +

+ +

+ Oops! Page Not Found +

+ +

+ Looks like this page took an impromptu detour. Let's get you back + on track! +

+ + + Return to Homepage + +
+
+ ); +} From bdbe685bd2dddc1375423de74faf97ce4278fa31 Mon Sep 17 00:00:00 2001 From: davidasix Date: Sun, 18 Jan 2026 16:43:58 -0500 Subject: [PATCH 10/14] Disable other pages --- src/app/login/{page.tsx => page.tsx.disabled} | 0 src/app/practice/{page.tsx => page.tsx.disabled} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/app/login/{page.tsx => page.tsx.disabled} (100%) rename src/app/practice/{page.tsx => page.tsx.disabled} (100%) diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx.disabled similarity index 100% rename from src/app/login/page.tsx rename to src/app/login/page.tsx.disabled diff --git a/src/app/practice/page.tsx b/src/app/practice/page.tsx.disabled similarity index 100% rename from src/app/practice/page.tsx rename to src/app/practice/page.tsx.disabled From 7116b53b640e6c459ddff443f29ab177d520f7f1 Mon Sep 17 00:00:00 2001 From: davidasix Date: Sun, 18 Jan 2026 16:55:28 -0500 Subject: [PATCH 11/14] Lint --- src/app/_components/loops-waitlist-form.tsx | 5 +---- src/app/practice/_components/dock-menu.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/app/_components/loops-waitlist-form.tsx b/src/app/_components/loops-waitlist-form.tsx index f424634..9ef3d26 100644 --- a/src/app/_components/loops-waitlist-form.tsx +++ b/src/app/_components/loops-waitlist-form.tsx @@ -187,10 +187,7 @@ export default function WaitListForm() { function SignUpFormButton() { return ( - ); diff --git a/src/app/practice/_components/dock-menu.tsx b/src/app/practice/_components/dock-menu.tsx index 498a210..f9a9ba9 100644 --- a/src/app/practice/_components/dock-menu.tsx +++ b/src/app/practice/_components/dock-menu.tsx @@ -1,8 +1,8 @@ "use client"; import { cn } from "~/lib/utils"; -import { screens } from "../page"; -import { buttonVariants } from "~/components/ui/button"; +// import { screens } from "../page"; +// import { buttonVariants } from "~/components/ui/button"; export function DockMenu({ activeScreenId }: { activeScreenId: string }) { return ( @@ -12,7 +12,7 @@ export function DockMenu({ activeScreenId }: { activeScreenId: string }) { "border-border fixed inset-x-0 bottom-0 left-1/2 z-50 w-min -translate-1/2 rounded-full border px-2.5 py-1.5 backdrop-blur-lg", )} > - {screens.map((screen) => { + {/* {screens.map((screen) => { const Icon = screen.icon; const isActive = activeScreenId === screen.id; @@ -31,7 +31,7 @@ export function DockMenu({ activeScreenId }: { activeScreenId: string }) {
); - })} + })} */} ); } From 04b6ab4ee46dc363a9831678576bb188076e2e5e Mon Sep 17 00:00:00 2001 From: davidasix Date: Sun, 18 Jan 2026 17:17:47 -0500 Subject: [PATCH 12/14] Get rid of dumb loader tracker --- src/components/navigation.tsx | 60 +++++++++++++++-------------------- 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/src/components/navigation.tsx b/src/components/navigation.tsx index 4ce8ae1..76a04b9 100644 --- a/src/components/navigation.tsx +++ b/src/components/navigation.tsx @@ -1,5 +1,5 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ "use client"; - import { useState, useEffect } from "react"; import Link from "next/link"; import { useSession, signOut } from "next-auth/react"; @@ -21,12 +21,6 @@ export function Navigation() { const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const { data: session } = useSession(); const { theme, setTheme } = useTheme(); - const [mounted, setMounted] = useState(false); - - // Prevent hydration mismatch for theme-dependent UI - useEffect(() => { - setMounted(true); - }, []); // Scroll detection useEffect(() => { @@ -70,20 +64,18 @@ export function Navigation() { */} {/* Theme Toggle */} - {mounted && ( - - )} + {/* Auth Section */} {/* {session ? ( @@ -116,20 +108,18 @@ export function Navigation() { {/* Mobile Menu Button */}
{/* Mobile Theme Toggle */} - {mounted && ( - - )} + {/*