diff options
author | polwex <polwex@sortug.com> | 2025-05-29 15:54:51 +0700 |
---|---|---|
committer | polwex <polwex@sortug.com> | 2025-05-29 15:54:51 +0700 |
commit | 7de09570c0d7907424c30f492207e80ff69e4061 (patch) | |
tree | 5f0971b9eeac9e1cc6506954843093b6b77ebd63 /src/pages | |
parent | 84c5b778039102a77b7fda2ddcab2bbf70085bdc (diff) |
very pretty
Diffstat (limited to 'src/pages')
-rw-r--r-- | src/pages/_layout.tsx | 8 | ||||
-rw-r--r-- | src/pages/index.tsx | 258 | ||||
-rw-r--r-- | src/pages/logout.tsx | 49 |
3 files changed, 251 insertions, 64 deletions
diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index 7f6a434..c19c1fb 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -1,9 +1,7 @@ import "../styles.css"; import type { ReactNode } from "react"; - -import { Header } from "../components/header"; -import { Footer } from "../components/footer"; +import { getContextData } from "waku/middleware/context"; type RootLayoutProps = { children: ReactNode }; @@ -11,10 +9,10 @@ export default async function RootLayout({ children }: RootLayoutProps) { const data = await getData(); return ( - <div className="font-['Nunito']"> + <div className="font-sans antialiased"> <meta name="description" content={data.description} /> <link rel="icon" type="image/png" href={data.icon} /> - <main className="m-6 items-center *:min-h-64 *:min-w-64 lg:m-0 lg:min-h-svh lg:justify-center"> + <main className="min-h-screen"> {children} </main> </div> diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 48fa46e..7b66f5d 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,92 +1,232 @@ import { Link } from "waku"; +import { getContextData } from "waku/middleware/context"; +import { ArrowRightIcon, BookOpenIcon, BrainIcon, LanguagesIcon, GraduationCapIcon } from "lucide-react"; import { Progress } from "@/components/ui/progress"; -import { getContextData } from "waku/middleware/context"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import Navbar from "@/components/Navbar"; type LanguageChoice = "th" | "en" | "zh" | "ja" | "es" | "fr"; -type LangMeta = { flag: string; name: string }; +type LangMeta = { flag: string; name: string; level?: string; progress?: number; totalCards?: number; dueCards?: number }; + const langs: Record<LanguageChoice, LangMeta> = { - th: { flag: "🇹ðŸ‡", name: "Thai" }, - en: { flag: "🇬🇧", name: "English" }, - zh: { flag: "🇨🇳", name: "Chinese" }, - ja: { flag: "🇯🇵", name: "Japanese" }, - es: { flag: "🇪🇸", name: "Spanish" }, - fr: { flag: "🇫🇷", name: "French" }, + th: { flag: "🇹ðŸ‡", name: "Thai", level: "Beginner", progress: 32, totalCards: 245, dueCards: 12 }, + en: { flag: "🇬🇧", name: "English", level: "Advanced", progress: 87, totalCards: 542, dueCards: 5 }, + zh: { flag: "🇨🇳", name: "Chinese", level: "Intermediate", progress: 59, totalCards: 378, dueCards: 8 }, + ja: { flag: "🇯🇵", name: "Japanese", level: "Beginner", progress: 23, totalCards: 198, dueCards: 15 }, + es: { flag: "🇪🇸", name: "Spanish", level: "Not Started", progress: 0, totalCards: 312, dueCards: 0 }, + fr: { flag: "🇫🇷", name: "French", level: "Not Started", progress: 0, totalCards: 289, dueCards: 0 }, }; export default async function HomePage() { - const { user } = getContextData(); + const { user } = getContextData() as any; + + // Get due cards count for the progress badge + const totalDueCards = Object.values(langs) + .reduce((sum, lang) => sum + (lang.dueCards || 0), 0); return ( <div className="min-h-screen bg-gray-50"> - <header className="bg-white shadow-sm sticky top-0 z-50"> + <Navbar user={user} /> + + {/* Hero section */} + <section className="bg-gradient-to-r from-indigo-600 to-indigo-700 text-white py-16"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> - <div className="flex justify-between items-center h-16"> - <div className="flex items-center"> - <h1 className="text-2xl font-bold text-indigo-600">Prosody</h1> + <div className="flex flex-col md:flex-row items-center"> + <div className="md:w-1/2 mb-8 md:mb-0"> + <h1 className="text-4xl md:text-5xl font-bold leading-tight mb-4"> + Master Languages with Sorlang + </h1> + <p className="text-lg md:text-xl mb-6 text-indigo-100"> + Boost your language learning with our scientifically proven spaced repetition system. Track progress, analyze text, and learn efficiently. + </p> + <div className="flex flex-wrap gap-4"> + <Link to="/study"> + <Button size="lg" className="bg-white text-indigo-700 hover:bg-indigo-50"> + Start Learning + <ArrowRightIcon className="ml-2 h-4 w-4" /> + </Button> + </Link> + <Link to="/parse"> + <Button size="lg" variant="outline" className="border-white text-white hover:bg-indigo-600"> + Analyze Text + </Button> + </Link> + </div> + </div> + <div className="md:w-1/2"> + <div className="flex justify-center"> + <div className="relative"> + <div className="absolute -top-4 -left-4 bg-indigo-500 text-white p-3 rounded-lg shadow-lg"> + 🇹🇠+ </div> + <div className="absolute top-8 -right-4 bg-indigo-500 text-white p-3 rounded-lg shadow-lg"> + 🇨🇳 + </div> + <div className="absolute -bottom-4 -left-4 bg-indigo-500 text-white p-3 rounded-lg shadow-lg"> + 🇯🇵 + </div> + <div className="absolute -bottom-4 right-4 bg-indigo-500 text-white p-3 rounded-lg shadow-lg"> + 🇬🇧 + </div> + <div className="bg-white rounded-xl p-8 shadow-xl"> + <div className="text-indigo-700 text-6xl font-bold mb-2"> + SRS + </div> + <div className="text-gray-600"> + Spaced Repetition System + </div> + </div> + </div> + </div> </div> - - {/* Desktop Navigation */} - <nav className="hidden md:flex space-x-8"> - <Link to="/"> - <button - className={`py-2 font-medium text-indigo-600 border-b-2 border-indigo-600`} - > - Home - </button> - </Link> - <Link to="/parse"> - <button - className={`py-2 font-medium text-gray-600 hover:text-indigo-600`} - > - Analyze Text - </button> - </Link> - </nav> </div> </div> - - {/* Mobile Navigation */} - </header> - <section className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 mb-8"> - <h2 className="text-lg"> Your Languages</h2> - <LanguageItem lang="en" /> - <LanguageItem lang="th" /> - <LanguageItem lang="zh" /> - <LanguageItem lang="ja" /> + </section> + + {/* Feature highlights */} + <section className="py-12 bg-white"> + <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> + <div className="text-center mb-12"> + <h2 className="text-3xl font-bold text-gray-900 mb-4">Learning Features</h2> + <p className="text-lg text-gray-600 max-w-3xl mx-auto"> + Tools designed to accelerate your language learning journey + </p> + </div> + + <div className="grid grid-cols-1 md:grid-cols-3 gap-8"> + <Card> + <CardHeader> + <div className="bg-indigo-100 w-12 h-12 rounded-lg flex items-center justify-center mb-2"> + <BrainIcon className="h-6 w-6 text-indigo-600" /> + </div> + <CardTitle>Spaced Repetition</CardTitle> + <CardDescription> + Optimized review schedule based on your performance + </CardDescription> + </CardHeader> + <CardContent> + <p className="text-gray-600"> + Our SRS algorithm determines the optimal time for you to review each card, helping you memorize efficiently. + </p> + </CardContent> + </Card> + + <Card> + <CardHeader> + <div className="bg-indigo-100 w-12 h-12 rounded-lg flex items-center justify-center mb-2"> + <LanguagesIcon className="h-6 w-6 text-indigo-600" /> + </div> + <CardTitle>Text Analysis</CardTitle> + <CardDescription> + Break down complex text into manageable pieces + </CardDescription> + </CardHeader> + <CardContent> + <p className="text-gray-600"> + Parse any text to analyze grammar, vocabulary, and patterns to enhance your understanding. + </p> + </CardContent> + </Card> + + <Card> + <CardHeader> + <div className="bg-indigo-100 w-12 h-12 rounded-lg flex items-center justify-center mb-2"> + <GraduationCapIcon className="h-6 w-6 text-indigo-600" /> + </div> + <CardTitle>Progress Tracking</CardTitle> + <CardDescription> + Monitor your learning journey with detailed statistics + </CardDescription> + </CardHeader> + <CardContent> + <p className="text-gray-600"> + Track your progress across different languages, see your mastery level, and identify areas for improvement. + </p> + </CardContent> + </Card> + </div> + </div> + </section> + + {/* Languages section */} + <section className="py-12 bg-gray-50"> + <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> + <div className="flex justify-between items-center mb-8"> + <h2 className="text-2xl font-bold text-gray-900">Your Languages</h2> + {totalDueCards > 0 && ( + <div className="bg-indigo-100 text-indigo-800 px-3 py-1 rounded-full text-sm font-medium"> + {totalDueCards} cards due for review + </div> + )} + </div> + + <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 mb-8"> + {Object.entries(langs).map(([langCode, langData]) => ( + <LanguageItem + key={langCode} + lang={langCode as LanguageChoice} + langData={langData} + /> + ))} + </div> + + <div className="text-center mt-8"> + <Link to="/study"> + <Button size="lg" className="bg-indigo-600 hover:bg-indigo-700"> + <BookOpenIcon className="mr-2 h-4 w-4" /> + Go to Study Dashboard + </Button> + </Link> + </div> + </div> </section> </div> ); } -const getData = async () => { - const data = { - title: "Waku", - headline: "Waku", - body: "Hello world!", - }; - - return data; -}; - export const getConfig = async () => { return { render: "dynamic", } as const; }; -async function LanguageItem({ lang }: { lang: LanguageChoice }) { +function LanguageItem({ lang, langData }: { lang: LanguageChoice, langData: LangMeta }) { return ( <Link to={`/lang/${lang}`}> - <div className="bg-white rounded-xl h-32 shadow-sm overflow-hidden hover:shadow-md transition-shadow duration-300"> - <div className="p-6"> - <div className="flex"> - <div className="text-lg">{langs[lang].flag}</div> - <div className="text-lg">{langs[lang].name}</div> + <Card className="hover:shadow-md transition-shadow duration-300 h-full"> + <CardHeader className="pb-2"> + <div className="flex items-center justify-between"> + <div className="flex items-center gap-3"> + <div className="text-3xl">{langData.flag}</div> + <div> + <CardTitle>{langData.name}</CardTitle> + <CardDescription>{langData.level}</CardDescription> + </div> + </div> + {langData.dueCards > 0 && ( + <div className="bg-red-100 text-red-800 px-2 py-1 rounded-full text-xs font-medium"> + {langData.dueCards} due + </div> + )} </div> - <Progress value={50} className="w-[60%]" /> - </div> - </div> + </CardHeader> + <CardContent> + <div className="mb-2"> + <Progress value={langData.progress} className="h-2" /> + <div className="flex justify-between mt-1 text-xs text-gray-500"> + <span>{langData.progress}% complete</span> + <span>{langData.totalCards} cards</span> + </div> + </div> + </CardContent> + <CardFooter className="pt-0"> + <Button variant="outline" className="w-full"> + {langData.progress > 0 ? "Continue Learning" : "Start Learning"} + </Button> + </CardFooter> + </Card> </Link> ); } diff --git a/src/pages/logout.tsx b/src/pages/logout.tsx new file mode 100644 index 0000000..880d175 --- /dev/null +++ b/src/pages/logout.tsx @@ -0,0 +1,49 @@ +import { getContextData } from "waku/middleware/context"; +import { useCookies } from "@/lib/server/cookiebridge"; +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import Navbar from "@/components/Navbar"; + +export default async function LogoutPage() { + const { user } = getContextData() as any; + const loggedIn = !!user; + + // If the user is logged in, delete the cookie + if (loggedIn) { + const { delCookie } = useCookies(); + delCookie("sorlang"); + } + + return ( + <div className="min-h-screen bg-gray-50"> + <Navbar user={null} /> + + <div className="container mx-auto py-16 px-4"> + <Card className="max-w-md mx-auto p-6 text-center"> + <h1 className="text-2xl font-bold mb-4"> + {loggedIn ? "You've been logged out" : "Already logged out"} + </h1> + <p className="text-gray-600 mb-6"> + {loggedIn + ? "Your session has been ended successfully. Thank you for using Sorlang." + : "You were not logged in."} + </p> + <div className="flex flex-col space-y-4"> + <Button asChild> + <a href="/login">Log back in</a> + </Button> + <Button variant="outline" asChild> + <a href="/">Return to home page</a> + </Button> + </div> + </Card> + </div> + </div> + ); +} + +export const getConfig = async () => { + return { + render: "dynamic", + } as const; +};
\ No newline at end of file |