Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Database migrations (auto-generated)
src/server/db/migrations/
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"cSpell.words": [
"Mikey",
"topicker"
]
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"lucide-react": "^0.553.0",
"next": "^15.5.9",
"next-auth": "5.0.0-beta.30",
"next-themes": "^0.4.6",
"nodemailer": "^7.0.12",
"postgres": "^3.4.4",
"react": "^19.0.0",
Expand Down
14 changes: 14 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added public/mikey-idea.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/mikey-watch-tall.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/mikey-watch.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/mikey.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 22 additions & 5 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ import "~/styles/globals.css";
import { type Metadata } from "next";
import { SessionProvider } from "next-auth/react";
import { Geist } from "next/font/google";
import HolyLoader from "holy-loader";

import { TRPCReactProvider } from "~/trpc/react";
import { ThemeProvider } from "~/components/theme-provider";
import { Navigation } from "~/components/navigation";
import { Footer } from "~/components/footer";

export const metadata: Metadata = {
title: "Create T3 App",
description: "Generated by create-t3-app",
title: "TableTopicker - Practice Impromptu Speaking",
description:
"Improve your impromptu speaking skills with timed practice sessions, AI-generated topics, and progress tracking. Start speaking with confidence today.",
icons: [{ rel: "icon", url: "/favicon.ico" }],
};

Expand All @@ -21,10 +26,22 @@ export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en" className={`${geist.variable}`}>
<html lang="en" className={`${geist.variable}`} suppressHydrationWarning>
<HolyLoader color="var(--accent)" height={4} />
<SessionProvider>
<body>
<TRPCReactProvider>{children}</TRPCReactProvider>
<body className="flex min-h-screen flex-col">
<TRPCReactProvider>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<Navigation />
<main className="flex-1">{children}</main>
<Footer />
</ThemeProvider>
</TRPCReactProvider>
</body>
</SessionProvider>
</html>
Expand Down
210 changes: 166 additions & 44 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,182 @@
import Link from "next/link";

import { auth } from "~/server/auth";
import Image from "next/image";
import { Clock, TrendingUp, Sparkles, Star } from "lucide-react";
import { Button } from "~/components/ui/button";
import {
Card,
CardDescription,
CardHeader,
CardTitle,
} from "~/components/ui/card";
import { Badge } from "~/components/ui/badge";
import { HydrateClient } from "~/trpc/server";

export default async function Home() {
const session = await auth();

const user = session?.user;

return (
<HydrateClient>
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white">
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16">
<h1 className="text-5xl font-extrabold tracking-tight sm:text-[5rem]">
Create <span className="text-[hsl(280,100%,70%)]">T3</span> App.
Hello {user?.email}
</h1>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-8">
<Link
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 hover:bg-white/20"
href="https://create.t3.gg/en/usage/first-steps"
target="_blank"
>
<h3 className="text-2xl font-bold">First Steps →</h3>
<div className="text-lg">
Just the basics - Everything you need to know to set up your
database and authentication.
<section className="relative overflow-hidden px-4 py-16 md:py-24">
<div className="mx-auto max-w-7xl">
<div className="grid items-center gap-12 md:grid-cols-2">
<div className="space-y-8">
<h1 className="text-5xl leading-tight font-extrabold tracking-tight md:text-7xl">
Practice <span className="text-primary">Impromptu</span>{" "}
<span className="text-accent">Speaking</span>
</h1>
<p className="text-muted-foreground text-lg md:text-xl">
Practice table-topics and hone your skills. Track your progress
and build confidence with timed speaking sessions.
</p>
<div className="flex flex-col gap-4 sm:flex-row">
<Link href="/practice">
<Button size="lg" className="hover-wobble w-full sm:w-auto">
Try It Now
</Button>
</Link>
<Link href="/login">
<Button
size="lg"
variant="outline"
className="w-full sm:w-auto"
>
Create Account
</Button>
</Link>
</div>
</Link>
<Link
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 hover:bg-white/20"
href="https://create.t3.gg/en/introduction"
target="_blank"
>
<h3 className="text-2xl font-bold">Documentation →</h3>
<div className="text-lg">
Learn more about Create T3 App, the libraries it uses, and how
to deploy it.
</div>

<div className="bg-primary/5 border-primary/20 relative hidden rounded-2xl border-2 p-8 md:block">
<div className="relative flex h-100 items-center justify-center">
<Image
src="/mikey.webp"
alt="Mikey the microphone mascot with encouraging expression"
width={300}
height={400}
className="-scale-x-100 object-contain"
priority
/>
</div>
</Link>
<Star className="text-accent absolute top-8 right-8 h-6 w-6 animate-pulse" />
<Star className="text-accent absolute bottom-12 left-8 h-4 w-4 animate-pulse delay-75" />
</div>
</div>
<div className="flex flex-col items-center gap-2">
<div className="flex flex-col items-center justify-center gap-4">
<p className="text-center text-2xl text-white">
{session && <span>Logged in as {session.user?.name}</span>}
</div>
</section>

<section className="bg-muted/30 overflow-x-hidden px-4 py-16 md:py-24">
<div className="mx-auto max-w-7xl">
<div className="flex items-center justify-between gap-8">
{/* Left Mikey - visible on large screens */}
<div className="relative hidden h-48 w-48 shrink-0 sm:block lg:hidden">
<Image
src="/mikey-watch-tall.webp"
alt="Mikey holding a stopwatch for timed practice"
fill
className="object-contain"
/>
</div>

<div className="mb-12 flex-1 text-center">
<h2 className="mb-4 text-3xl font-bold md:text-4xl">
Everything You Need to{" "}
<span className="text-primary">Level</span>{" "}
<span className="text-accent">Up</span>
</h2>
<p className="text-muted-foreground mx-auto max-w-2xl text-lg">
Whether you&apos;re preparing for a contest or just practicing
to stay sharp, TableTopicker can help!
</p>
<Link
href={session ? "/api/auth/signout" : "/api/auth/signin"}
className="rounded-full bg-white/10 px-10 py-3 font-semibold no-underline transition hover:bg-white/20"
>
{session ? "Sign out" : "Sign in"}
</Link>
</div>

{/* Right Mikey - visible on large screens */}
<div className="relative hidden h-48 w-48 shrink-0 sm:block lg:hidden">
<Image
src="/mikey-idea.webp"
alt="Mikey with a lightbulb idea for AI-generated topics"
fill
className="-scale-x-100 object-contain"
/>
</div>
</div>

<div className="grid gap-6 overflow-visible lg:grid-cols-3">
<Card className="group border-primary/20 relative overflow-visible transition-all hover:scale-[1.0025] hover:shadow-lg">
<CardHeader className="relative z-10">
<div className="bg-primary/10 mb-4 flex h-16 w-16 items-center justify-center rounded-2xl">
<Clock className="text-primary h-8 w-8" />
</div>
<CardTitle>Timed Practice</CardTitle>
<CardDescription>
1-2 minute rounds with built-in timer and stop-light color
notifiers. Speak concisely and confidently.
</CardDescription>
</CardHeader>
<div className="absolute bottom-0 left-0 hidden h-72 w-72 -translate-x-[70%] lg:block">
<Image
src="/mikey-watch-tall.webp"
alt="Mikey holding a stopwatch for timed practice"
fill
className="object-contain"
/>
</div>
</Card>

<Card className="group border-primary/20 transition-all hover:scale-[1.0025] hover:shadow-lg">
<CardHeader>
<div className="bg-accent/10 mb-4 flex h-16 w-16 items-center justify-center rounded-2xl">
<TrendingUp className="text-accent h-8 w-8" />
</div>
<CardTitle>Track Your Progress</CardTitle>
<CardDescription>
Rate your performance. Watch your skills grow over time
through self analysis.
</CardDescription>
</CardHeader>
</Card>

<Card className="group border-primary/20 relative overflow-visible transition-all hover:scale-[1.0025] hover:shadow-lg">
<CardHeader className="relative z-10">
<div className="bg-accent/10 mb-4 flex h-16 w-16 items-center justify-center rounded-2xl">
<Sparkles className="text-accent h-8 w-8" />
</div>
<CardTitle className="flex items-center gap-2">
AI-Generated Topics
<Badge variant="secondary" className="bg-accent/20">
Premium
</Badge>
</CardTitle>
<CardDescription>
Unlimited questions for any theme you can imagine.
</CardDescription>
</CardHeader>
<div className="absolute right-0 -bottom-10 hidden h-72 w-72 translate-x-[70%] lg:block">
<Image
src="/mikey-idea.webp"
alt="Mikey with a lightbulb idea for AI-generated topics"
fill
className="-scale-x-100 object-contain"
/>
</div>
</Card>
</div>
</div>
</section>

<section className="relative overflow-hidden px-4 py-16 md:py-24">
<div className="bg-primary/5 absolute inset-0" />
<div className="relative mx-auto max-w-4xl text-center">
<h2 className="mb-16 text-3xl font-bold md:text-5xl">
<i>All</i> your conversations are{" "}
<span className="text-primary">impromptu</span> so it&apos;s
something you should <span className="text-accent">practice</span>.
</h2>

<Link href="/practice">
<Button size="lg" className="hover-wobble h-14 w-72 text-2xl">
Get Started
</Button>
</Link>
</div>
</main>
</section>
</HydrateClient>
);
}
Loading